diff options
| author | Jari Vetoniemi <jari.vetoniemi@indooratlas.com> | 2020-03-16 18:49:26 +0900 | 
|---|---|---|
| committer | Jari Vetoniemi <jari.vetoniemi@indooratlas.com> | 2020-03-30 00:39:06 +0900 | 
| commit | fcbf63e62c627deae76c1b8cb8c0876c536ed811 (patch) | |
| tree | 64cb17de3f41a2b6fef2368028fbd00349946994 /jni/ruby/test/rexml/xpath | |
Fresh start
Diffstat (limited to 'jni/ruby/test/rexml/xpath')
| -rw-r--r-- | jni/ruby/test/rexml/xpath/test_attribute.rb | 29 | ||||
| -rw-r--r-- | jni/ruby/test/rexml/xpath/test_axis_preceding_sibling.rb | 39 | ||||
| -rw-r--r-- | jni/ruby/test/rexml/xpath/test_base.rb | 1089 | ||||
| -rw-r--r-- | jni/ruby/test/rexml/xpath/test_node.rb | 42 | ||||
| -rw-r--r-- | jni/ruby/test/rexml/xpath/test_predicate.rb | 82 | ||||
| -rw-r--r-- | jni/ruby/test/rexml/xpath/test_text.rb | 74 | 
6 files changed, 1355 insertions, 0 deletions
| diff --git a/jni/ruby/test/rexml/xpath/test_attribute.rb b/jni/ruby/test/rexml/xpath/test_attribute.rb new file mode 100644 index 0000000..95af4de --- /dev/null +++ b/jni/ruby/test/rexml/xpath/test_attribute.rb @@ -0,0 +1,29 @@ +require 'test/unit' +require 'rexml/document' + +module REXMLTests +  class TestXPathAttribute < Test::Unit::TestCase +    def setup +      @xml = <<-XML +<?xml version="1.0" encoding="UTF-8"?> +<root> +  <child name="one">child1</child> +  <child name="two">child2</child> +  <child name="three">child3</child> +</root> +      XML +      @document = REXML::Document.new(@xml) +    end + +    def test_elements +      root = @document.elements["root"] +      second_child = root.elements["child[@name='two']"] +      assert_equal("child2", second_child.text) +    end + +    def test_xpath_each +      children = REXML::XPath.each(@document, "/root/child[@name='two']") +      assert_equal(["child2"], children.collect(&:text)) +    end +  end +end diff --git a/jni/ruby/test/rexml/xpath/test_axis_preceding_sibling.rb b/jni/ruby/test/rexml/xpath/test_axis_preceding_sibling.rb new file mode 100644 index 0000000..2731807 --- /dev/null +++ b/jni/ruby/test/rexml/xpath/test_axis_preceding_sibling.rb @@ -0,0 +1,39 @@ +require "test/unit/testcase" +require "rexml/document" + +module REXMLTests +  class TestXPathAxisPredcedingSibling < Test::Unit::TestCase +    include REXML +    SOURCE = <<-EOF +      <a id='1'> +        <e id='2'> +          <f id='3'/> +          <f id='4'/> +          <f id='5'/> +          <f id='6'/> +        </e> +      </a> +      EOF + +    def setup +      @@doc = Document.new(SOURCE) unless defined? @@doc +    end + +    def test_preceding_sibling_axis +      context = XPath.first(@@doc,"/a/e/f[last()]") +      assert_equal "6", context.attributes["id"] + +      prev = XPath.first(context, "preceding-sibling::f") +      assert_equal "5", prev.attributes["id"] + +      prev = XPath.first(context, "preceding-sibling::f[1]") +      assert_equal "5", prev.attributes["id"] + +      prev = XPath.first(context, "preceding-sibling::f[2]") +      assert_equal "4", prev.attributes["id"] + +      prev = XPath.first(context, "preceding-sibling::f[3]") +      assert_equal "3", prev.attributes["id"] +    end +  end +end diff --git a/jni/ruby/test/rexml/xpath/test_base.rb b/jni/ruby/test/rexml/xpath/test_base.rb new file mode 100644 index 0000000..a57ba63 --- /dev/null +++ b/jni/ruby/test/rexml/xpath/test_base.rb @@ -0,0 +1,1089 @@ +require_relative "../rexml_test_utils" + +require "rexml/document" + +module REXMLTests +  class TestXPathBase < Test::Unit::TestCase +    include REXMLTestUtils +    include REXML +    SOURCE = <<-EOF +      <a id='1'> +        <b id='2' x='y'> +          <c id='3'/> +          <c id='4'/> +        </b> +        <d id='5'> +          <c id='6' x='y'/> +          <c id='7'/> +          <c id='8'/> +          <q id='19'/> +        </d> +        <e id='9'> +          <f id='10' a='b'/> +          <f id='11' a='c'/> +          <f id='12' a='d'> +            <g id='13'/> +          </f> +          <f id='14' a='d'/> +        </e> +        <m id='15'> +          <n id='16'> +            <o id='17'> +              <p id='18'/> +            </o> +          </n> +        </m> +      </a> +      EOF +    JENI_TENNISON = <<-EOJT +    <a> +      <b> +        <c> +          <d> +            <e id='x'> +              <f/> +            </e> +          </d> +        </c> +        <c> +          <d> +            <e id='y'/> +          </d> +        </c> +      </b> +      <b> +        <c> +          <d> +            <e id='z'/> +          </d> +        </c> +      </b> +    </a> +    EOJT + +    def setup +      @@doc = Document.new(SOURCE) unless defined? @@doc +      @@jeni = Document.new( JENI_TENNISON ) unless defined? @@jeni +    end + +    def each_test( element, xpath ) +      count = 0 +      XPath::each( element, xpath ) { |child| +        count += 1 +        yield child if block_given? +      } +      count +    end + +    def test_descendant +      doc = Document.new("<a><b><c id='1'/></b><d><b><c id='2'/></b></d></a>") +      p = XPath.match( doc, "//c" ) +      assert_equal( 2, p.size ) +      p = XPath.first( @@doc, "//p" ) +      assert_equal "p", p.name +      c = each_test( @@doc, "//c" ) { |child| assert_equal "c", child.name } +      assert_equal 5, c +      c = each_test( @@doc.root, "b//c" ) { |child| +          assert_equal "c", child.name +      } +      assert_equal 2, c + +      doc = Document.new( "<a><z id='1'/><b><z id='11'/><z id='12'/></b><c><z id='21'/><z id='22'/><d><z id='31'/><z id='32'/></d></c></a>" ) +      # //para[1] : all descendants which are the first para child of their parent +      assert_equal( 4, XPath.match( doc, "//z[1]" ).size ) +      # /descendant::para[1] : the first descendant para element +      assert_equal( 1, XPath.match( doc, "/descendant::z[1]" ).size ) +    end + +    def test_root +      source = "<a><b/></a>" +      doc = Document.new( source ) +      assert_equal doc, doc.root_node +      assert_equal "a", XPath::first( doc, "/" ).elements[1].name +    end + +    def test_abbreviated_simple_child +      assert_equal "a", XPath::first(@@doc, "a").name +    end + +    def test_child +      c = XPath::first( @@doc, "a/b/c" ) +      assert_equal "c", c.name +      assert_equal "3", XPath::first(@@doc, "a/b/c").attributes["id"] +    end + +    def test_root_child +      assert_equal "a", XPath::first(@@doc, "/a").name +      c = XPath::first( @@doc, "a/b/c" ) +      assert_equal "a", XPath::first(c, "/a").name +    end + +    def test_root_children +      c = XPath::first( @@doc, "a/b/c" ) +      assert_equal "2", XPath::first(c, "/a/b").attributes["id"] +    end + +    def test_abbreviated_step +      c = XPath::first( @@doc, "a/b/c" ) +      assert_equal("c", c.name) +      assert_equal("a", XPath::first(@@doc.root, ".").name) +      assert_equal("b", XPath::first(c, "..").name) +      assert_equal("a", XPath::first(@@doc, "a/b/..").name) + +      doc = File.open(fixture_path("project.xml")) do |f| +        REXML::Document.new(f) +      end +      c = each_test(doc.root, "./Description" ) { |child| +        assert_equal("Description",child.name) +      } +      assert_equal 1, c +    end + +    # Things that aren't tested elsewhere +    def test_predicates +      assert_equal "12", XPath::first(@@doc, "a/e/f[3]").attributes["id"] +      assert_equal "13", XPath::first(@@doc, "a/e/f[3]/g").attributes["id"] +      assert_equal "14", XPath::first(@@doc, "a/e/f[@a='d'][2]").attributes["id"] +      assert_equal "14", XPath::first(@@doc, "a/e/f[@a='d'][@id='14']").attributes["id"] +      assert_equal "a", XPath::first( @@doc, "*[name()='a' and @id='1']" ).name +      c=each_test( @@doc, "//*[name()='f' and @a='d']") { |i| +        assert_equal "f", i.name +      } +      assert_equal 2, c +      c=each_test( @@doc, "//*[name()='m' or @a='d']") { |i| +        assert ["m","f"].include?(i.name) +      } +      assert_equal 3, c + +      assert_equal "b", XPath::first( @@doc, "//b[@x]" ).name +    end + +    def test_node_type +      doc = Document.new "<a><?foo bar?><!--comment-->text</a>" +      #res = XPath::first(doc.root, "text()") +      #assert_equal "text", res.to_s + +      #res = XPath::first(doc, "*") +      #assert_equal "a", res.name + +      assert_equal( :processing_instruction, +      XPath::first(doc.root, "processing-instruction()").node_type) +      assert_equal( :comment, XPath::first(doc.root, "comment()").node_type) +    end + +    def test_functions +      # trivial text() test +      # confuse-a-function +      source = "<a>more <b id='1'/><b id='2'>dumb</b><b id='3'/><c/> text</a>" +      doc = Document.new source +      res = "" +      #XPath::each(doc.root, "text()") {|val| res << val.to_s} +      #assert_equal "more  text", res + +      #res = XPath::first(doc.root, "b[last()]") +      #assert_equal '3', res.attributes['id'] +      res = XPath::first(doc.root, "b[position()=2]") +      assert_equal '2', res.attributes['id'] +      res = XPath::first(doc.root, "*[name()='c']") +      assert_equal "c", res.name +    end + +    def no_test_ancestor +      doc = REXML::Document.new(File.new(fixture_path("testsrc.xml"))) +      doc.elements.each("//item") { |el| print el.name +        if el.attributes['x'] +          puts " -- "+el.attributes['x'] +        else +          puts +        end +      } +      doc.elements.each("//item/ancestor::") { |el| print el.name +        if el.attributes['x'] +          puts " -- "+el.attributes['x'] +        else +          puts +        end +      } +    end + +    # Here are some XPath tests that were originally submitted by ... +    # The code has changed some, but the logic and the source documents are the +    # same. +    # This method reads a document from a file, and then a series of xpaths, +    # also from a file.  It then checks each xpath against the source file. +    def test_more +      xmlsource   = fixture_path("testsrc.xml") +      xpathtests  = fixture_path("xp.tst") + +      doc = File.open(xmlsource) {|f| REXML::Document.new(f) } +      #results = "" +      results = REXML::Document.new +      results.add_element "test-results" +      File.foreach(xpathtests) do |line| +        line.strip! +        begin +          doc.root +          #puts "#"*80 +          #print "\nDoing #{line} " ; $stdout.flush +          doc.elements.each(line) do |el| +            #print "." ; $stdout.flush +            results.root << el.clone +            #results << el.to_s +          end +          #ObjectSpace.garbage_collect +          GC::start +        rescue Exception => z +          #puts "\n'#{line}' failed" +          fail("Error on line #{line}:\n#{z.message}\n"+z.backtrace[0,10].join("\n")) +          #results.root.add_element( "error", {"path"=>line}).text = z.message+"\n"+z.backtrace[0,10].join("\n") +          #results << "<error path='"+line+"'>"+z.message+"</error>" +        end +      end +    end + +    def test_axe_descendant +      assert_equal "f", XPath::first( @@doc, "descendant::f").name +    end + +    def test_axe_parent +      q = XPath.first( @@doc, "a/d/c/parent::*/q" ) +      assert_equal 19, q.attributes["id"].to_i +    end + +    def test_abbreviated_attribute +      assert_equal 'a', XPath::first( @@doc, "a[@id='1']" ).name +      c = XPath::first( @@doc, "a/b/c[@id='4']" ) +      assert_equal 'c', c.name +      assert_equal '4', c.attributes['id'] + +      result = XPath::first( @@doc, "descendant::f[@a='c']") +      assert_equal "11", result.attributes['id'] + +      assert_equal "11", XPath::first(@@doc, "a/e/f[@a='c']").attributes["id"] +      assert_equal "11", XPath::first(@@doc, "a/e/*[@a='c']").attributes["id"] +    end + +    def test_axe_self +      c = XPath::first( @@doc, "a/b/c" ) +      assert c +      assert_equal "c", c.name +      assert_equal "c", XPath::first( c, "self::node()" ).name +    end + +    def test_axe_ancestor +      doc = REXML::Document.new " +      <a> +        <b id='1'> +          <c> +            <b id='2'> +              <d/> +            </b> +          </c> +        </b> +      </a>" + +      d = XPath.first( doc, "//d" ) +      assert_equal "d", d.name +      b = each_test( d, "ancestor::b" ) { |el| +        assert((1..2) === el.attributes['id'].to_i, +          "Expected #{el.attributes['id']} to be either 1 or 2" +        ) +      } +      assert_equal 2, b +    end + +    def test_axe_child +      m = XPath.first( @@doc, "a/child::m" ) +      assert_equal 15, m.attributes['id'].to_i +    end + +    def test_axe_attribute +      a = XPath.first( @@doc, "a/attribute::id" ) +      assert_equal "1", a.value +      a = XPath.first( @@doc, "a/e/f[@id='14']/attribute::a" ) +      assert_equal "d", a.value +    end + +    def test_axe_sibling +      doc = Document.new "<a><b><c/></b><e><f id='10'/><f id='11'/><f id='12'/></e></a>" +      first_f = XPath.first( doc, "a/e/f" ) +      assert first_f +      assert_equal '10', first_f.attributes['id'] +      next_f = XPath.first( doc, "a/e/f/following-sibling::node()" ) +      assert_equal '11', next_f.attributes['id'] + +      b = XPath.first( doc, "a/e/preceding-sibling::node()" ) +      assert_equal 'b', b.name +    end + +    def test_lang +      doc = File.open(fixture_path("lang0.xml")) {|f| Document.new(f) } +      #puts IO.read( "test/lang.xml" ) + +      #puts XPath.match( doc, "//language/*" ).size +      c = each_test( doc, "//language/*" ) { |element| +        #puts "#{element.name}: #{element.text}" +      } +      assert_equal 4, c +    end + +    def test_namespaces_1 +      source = <<-EOF +        <foo xmlns:ts="this" xmlns:tt="that"> +          <ts:bar>this bar</ts:bar> +          <tt:bar>that bar</tt:bar> +        </foo> +      EOF +      doc = Document.new source +      XPath.each( doc, "//bar" ) { +        fail "'bar' should match nothing in this case" +      } + +      namespace = {"t"=>"this"} +      results = XPath.first( doc, "//t:bar", namespace ) +      assert_equal "this bar", results.text +    end + +    def test_namespaces_2 +      source = <<-EOF +        <foo xmlns:ts="this" xmlns:tt="that"> +          <ts:bar>this bar</ts:bar> +          <tt:bar>that bar</tt:bar> +        </foo> +      EOF +      doc = Document.new source +      res = XPath::first(doc, "//*[local_name()='bar']") +      assert res, "looking for //*[name()='bar']" +      assert_equal 'this', res.namespace +      res = XPath::first(doc.root, "*[namespace_uri()='that']") +      assert_equal 'that bar', res.text +    end + +    def test_complex +      next_f = XPath.first( @@doc, "a/e/f[@id='11']/following-sibling::*" ) +      assert_equal 12, next_f.attributes['id'].to_i +      prev_f = XPath.first( @@doc, "a/e/f[@id='11']/preceding-sibling::*" ) +      assert_equal 10, prev_f.attributes['id'].to_i +      c = each_test( @@doc, "descendant-or-self::*[@x='y']" ) +      assert_equal 2, c +    end + +    def test_grouping +      t = XPath.first( @@doc, "a/d/*[name()='d' and (name()='f' or name()='q')]" ) +      assert_nil t +      t = XPath.first( @@doc, "a/d/*[(name()='d' and name()='f') or name()='q']" ) +      assert_equal 'q', t.name +    end + +    def test_preceding +      d = Document.new "<a><b id='0'/><b id='2'/><b><c id='0'/><c id='1'/><c id='2'/></b><b id='1'/></a>" +      start = XPath.first( d, "/a/b[@id='1']" ) +      assert_equal 'b', start.name +      c = XPath.first( start, "preceding::c" ) +      assert_equal '2', c.attributes['id'] + +      c1, c0 = XPath.match( d, "/a/b/c[@id='2']/preceding::node()" ) +      assert_equal '1', c1.attributes['id'] +      assert_equal '0', c0.attributes['id'] + +      c2, c1, c0, b, b2, b0 = XPath.match( start, "preceding::node()" ) + +      assert_equal 'c', c2.name +      assert_equal 'c', c1.name +      assert_equal 'c', c0.name +      assert_equal 'b', b.name +      assert_equal 'b', b2.name +      assert_equal 'b', b0.name + +      assert_equal '2', c2.attributes['id'] +      assert_equal '1', c1.attributes['id'] +      assert_equal '0', c0.attributes['id'] +      assert b.attributes.empty? +      assert_equal '2', b2.attributes['id'] +      assert_equal '0', b0.attributes['id'] + +      d = REXML::Document.new("<a><b/><c/><d/></a>") +      matches = REXML::XPath.match(d, "/a/d/preceding::node()") +      assert_equal("c", matches[0].name) +      assert_equal("b", matches[1].name) + +      s = "<a><b><c id='1'/></b><b><b><c id='2'/><c id='3'/></b><c id='4'/></b><c id='NOMATCH'><c id='5'/></c></a>" +      d = REXML::Document.new(s) +      c = REXML::XPath.match( d, "//c[@id = '5']") +      cs = REXML::XPath.match( c, "preceding::c" ) +      assert_equal( 4, cs.length ) +    end + +    def test_following +      d = Document.new "<a><b id='0'/><b/><b><c id='1'/><c id='2'/></b><b id='1'/></a>" +      start = XPath.first( d, "/a/b[@id='0']" ) +      assert_equal 'b', start.name +      c = XPath.first( start, "following::c" ) +      assert_equal '1', c.attributes['id'] + +      s = "<a><b><c><d/></c><e/></b><f><g><h/><i/></g></f><i/></a>" +      d = Document.new(s) +      c = XPath.first(d, '/a/b/c') +      assert_equal 'c', c.name +      res = XPath.match( c, 'following::*' ) +      assert_equal 6, res.size +      res = XPath.match( c, 'following::i' ) +      assert_equal 2, res.size +    end + +    # The following three paths were provided by +    # Jeni Tennison <jeni@jenitennison.com> +    # a consultant who is also an XSL and XPath expert +    #def test_child_cubed +    #  els = @@jeni.elements.to_a("*****") +    #  assert_equal 3, els.size +    #end + +    #def test_div_2 +    #  results = doc.elements.to_a("/ div 2") +    #end + +    #def test_nested_predicates +    #  puts @@jeni.root.elements[1].elements[1].name +    #  results = @@jeni.root.elements[1].elements[1].elements.to_a("../following-sibling::*[*[name() = name(current())]]") +    #  puts results +    #end + +    # Contributed by Mike Stok +    def test_starts_with +      source = <<-EOF +        <foo> +        <a href="mailto:a@b.c">a@b.c</a> +        <a href="http://www.foo.com">http://www.foo.com</a> +        </foo> +      EOF +      doc = Document.new source +      mailtos = doc.elements.to_a("//a[starts-with(@href, 'mailto:')]") +      assert_equal 1, mailtos.size +      assert_equal "mailto:a@b.c", mailtos[0].attributes['href'] + +      ailtos = doc.elements.to_a("//a[starts-with(@href, 'ailto:')]") +      assert_equal 0, ailtos.size +    end + +    def test_toms_text_node +      file = "<a>A<b>B</b><c>C<d>D</d>E</c>F</a>" +      doc = Document.new(file) +      assert_equal 'A', XPath.first(doc[0], 'text()').to_s +      assert_equal 'AF', XPath.match(doc[0], 'text()').collect { |n| +        n.to_s +      }.join('') +      assert_equal 'B', XPath.first(doc[0], 'b/text()').to_s +      assert_equal 'D', XPath.first(doc[0], '//d/text()').to_s +      assert_equal 'ABCDEF', XPath.match(doc[0], '//text()').collect {|n| +        n.to_s +      }.join('') +    end + +    def test_string_length +      doc = Document.new <<-EOF +        <AAA> +        <Q/> +        <SSSS/> +        <BB/> +        <CCC/> +        <DDDDDDDD/> +        <EEEE/> +        </AAA> +      EOF +      assert doc, "create doc" + +      set = doc.elements.to_a("//*[string-length(name()) = 3]") +      assert_equal 2, set.size, "nodes with names length = 3" + +      set = doc.elements.to_a("//*[string-length(name()) < 3]") +      assert_equal 2, set.size, "nodes with names length < 3" + +      set = doc.elements.to_a("//*[string-length(name()) > 3]") +      assert_equal 3, set.size, "nodes with names length > 3" +    end + +    # Test provided by Mike Stok +    def test_contains +      source = <<-EOF +        <foo> +        <a href="mailto:a@b.c">a@b.c</a> +        <a href="http://www.foo.com">http://www.foo.com</a> +        </foo> +      EOF +      doc = Document.new source + +      [ +      #['o', 2], +      ['foo', 1], ['bar', 0]].each { |search, expected| +        set = doc.elements.to_a("//a[contains(@href, '#{search}')]") +        assert_equal expected, set.size +      } +    end + +    # Mike Stok and Sean Russell +    def test_substring +      # examples from http://www.w3.org/TR/xpath#function-substring +      doc = Document.new('<test string="12345" />') + +      Document.new("<a b='1'/>") +      #puts XPath.first(d, 'node()[0 + 1]') +      #d = Document.new("<a b='1'/>") +      #puts XPath.first(d, 'a[0 mod 0]') +      [ [1.5, 2.6, '234'], +        [0, 3, '12'], +        [0, '0 div 0', ''], +        [1, '0 div 0', ''], +        ['-42', '1 div 0', '12345'], +        ['-1 div 0', '1 div 0', ''] +      ].each { |start, length, expected| +        set = doc.elements.to_a("//test[substring(@string, #{start}, #{length}) = '#{expected}']") +        assert_equal 1, set.size, "#{start}, #{length}, '#{expected}'" +      } +    end + +    def test_translate +      source = <<-EOF +      <doc> +      <case name='w3c one' result='BAr' />        <!-- w3c --> +      <case name='w3c two' result='AAA' />        <!-- w3c --> +      <case name='alchemy' result="gold" />   <!-- mike --> +      <case name='vbxml one' result='A Space Odyssey' /> +      <case name='vbxml two' result='AbCdEf' /> +      </doc> +      EOF + +      doc = Document.new(source) + +      [ ['bar', 'abc', 'ABC', 'w3c one'], +      ['--aaa--','abc-','ABC', 'w3c two'], +      ['lead', 'dear language', 'doll groover', 'alchemy'], +      ['A Space Odissei', 'i', 'y', 'vbxml one'], +      ['abcdefg', 'aceg', 'ACE', 'vbxml two'], +      ].each { |arg1, arg2, arg3, name| +        translate = "translate('#{arg1}', '#{arg2}', '#{arg3}')" +        set = doc.elements.to_a("//case[@result = #{translate}]") +        assert_equal 1, set.size, translate +        assert_equal name, set[0].attributes['name'] +      } +    end + +    def test_math +      d = Document.new( '<a><b/><c/></a>' ) +      assert XPath.first( d.root, 'node()[1]' ) +      assert_equal 'b', XPath.first( d.root, 'node()[1]' ).name +      assert XPath.first( d.root, 'node()[0 + 1]' ) +      assert_equal 'b', XPath.first( d.root, './node()[0 + 1]' ).name +      assert XPath.first( d.root, 'node()[1 + 1]' ) +      assert_equal 'c', XPath.first( d.root, './node()[1 + 1]' ).name +      assert XPath.first( d.root, 'node()[4 div 2]' ) +      assert_equal 'c', XPath.first( d.root, './node()[4 div 2]' ).name +      assert XPath.first( d.root, 'node()[2 - 1]' ) +      assert_equal 'b', XPath.first( d.root, './node()[2 - 1]' ).name +      assert XPath.first( d.root, 'node()[5 mod 2]' ) +      assert_equal 'b', XPath.first( d.root, './node()[5 mod 2]' ).name +      assert XPath.first( d.root, 'node()[8 mod 3]' ) +      assert_equal 'c', XPath.first( d.root, './node()[8 mod 3]' ).name +      assert XPath.first( d.root, 'node()[1 * 2]' ) +      assert_equal 'c', XPath.first( d.root, './node()[1 * 2]' ).name +      assert XPath.first( d.root, 'node()[2 + -1]' ) +      assert_equal 'b', XPath.first( d.root, './node()[2 + -1]' ).name +    end + +    def test_name +      assert_raise( UndefinedNamespaceException, "x should be undefined" ) { +        REXML::Document.new("<a x='foo'><b/><x:b/></a>") +      } +      d = REXML::Document.new("<a xmlns:x='foo'><b/><x:b/></a>") +      assert_equal 1, d.root.elements.to_a('*[name() = "b"]').size +      assert_equal 1, d.elements.to_a('//*[name() = "x:b"]').size +    end + +    def test_local_name +      d = REXML::Document.new("<a xmlns:x='foo'><b/><x:b/></a>") +      assert_equal 2, d.root.elements.to_a('*[local_name() = "b"]').size +      assert_equal 2, d.elements.to_a('//*[local_name() = "b"]').size +    end + +    def test_comparisons +      source = "<a><b id='1'/><b id='2'/><b id='3'/></a>" +      doc = REXML::Document.new(source) + +      # NOTE TO SER: check that number() is required +      assert_equal 2, REXML::XPath.match(doc, "//b[number(@id) > 1]").size +      assert_equal 3, REXML::XPath.match(doc, "//b[number(@id) >= 1]").size +      assert_equal 1, REXML::XPath.match(doc, "//b[number(@id) <= 1]").size +      assert_equal 1, REXML::XPath.match(doc, "//b[number(@id) = (1 * 1)]").size +      assert_equal 1, REXML::XPath.match(doc, "//b[number(@id) = (1 mod 2)]").size +      assert_equal 1, REXML::XPath.match(doc, "//b[number(@id) = (4 div 2)]").size +    end + +    # Contributed by Kouhei +    def test_substring_before +      doc = Document.new("<r><a/><b/><c/></r>") +      assert_equal("a", doc.root.elements.to_a("*[name()=substring-before('abc', 'b')]")[0].name) +      assert_equal("c", doc.root.elements.to_a("*[name()=substring-after('abc', 'b')]")[0].name) +    end + +    def test_spaces +      doc = Document.new("<a> +        <b> +          <c id='a'/> +        </b> +        <c id='b'/> +      </a>") +      assert_equal( 1, REXML::XPath.match(doc, +        "//*[local-name()='c' and @id='b']").size ) +      assert_equal( 1, REXML::XPath.match(doc, +        "//*[ local-name()='c' and @id='b' ]").size ) +      assert_equal( 1, REXML::XPath.match(doc, +        "//*[ local-name() = 'c' and @id = 'b' ]").size ) +      assert_equal( 1, +        REXML::XPath.match(doc, '/a/c[@id]').size ) +      assert_equal( 1, +        REXML::XPath.match(doc, '/a/c[(@id)]').size ) +      assert_equal( 1, +        REXML::XPath.match(doc, '/a/c[ @id ]').size ) +      assert_equal( 1, +        REXML::XPath.match(doc, '/a/c[ (@id) ]').size ) +      assert_equal( 1, +        REXML::XPath.match(doc, '/a/c[( @id )]').size ) +      assert_equal( 1, REXML::XPath.match(doc.root, +        '/a/c[ ( @id ) ]').size ) +      assert_equal( 1, REXML::XPath.match(doc, +        '/a/c [ ( @id ) ] ').size ) +      assert_equal( 1, REXML::XPath.match(doc, +        ' / a / c [ ( @id ) ] ').size ) +    end + +    def test_text_nodes +      #  source = "<root> +      #<child/> +      #<child>test</child> +      #</root>" +      source = "<root><child>test</child></root>" +      d = REXML::Document.new( source ) +      r = REXML::XPath.match( d, %q{/root/child[text()="test"]} ) +      assert_equal( 1, r.size ) +      assert_equal( "child", r[0].name ) +      assert_equal( "test", r[0].text ) +    end + +    def test_auto_string_value +      source = "<root><foo/><title>Introduction</title></root>" +      d = REXML::Document.new( source ) +      #r = REXML::XPath.match( d, %q{/root[title="Introduction"]} ) +      #assert_equal( 1, r.size ) +      source = "<a><b/><c/><c>test</c></a>" +      d = REXML::Document.new( source ) +      r = REXML::XPath.match( d, %q{/a[c='test']} ) +      assert_equal( 1, r.size ) +      r = REXML::XPath.match( d, %q{a[c='test']} ) +      assert_equal( 1, r.size ) +      r = d.elements["/a[c='test']"] +      assert_not_nil( r ) +      r = d.elements["a[c='test']"] +      assert_not_nil( r ) +      r = d.elements["a[c='xtest']"] +      assert_nil( r ) +      r = REXML::XPath.match( d, %q{a[c='xtest']} ) +      assert_equal( 0, r.size ) +    end + +    def test_ordering +      source = "<a><b><c id='1'/><c id='2'/></b><b><d id='1'/><d id='2'/></b></a>" +      d = REXML::Document.new( source ) +      r = REXML::XPath.match( d, %q{/a/*/*[1]} ) +      assert_equal( 1, r.size ) +      r.each { |el| assert_equal( '1', el.attribute('id').value ) } +    end + +    def test_descendant_or_self_ordering +      source = "<a> +      <b> +        <c id='1'/> +        <c id='2'/> +      </b> +      <b> +        <d id='1'> +          <c id='3'/> +        </d> +        <d id='2'> +          <e> +            <c id='4'/> +          </e> +        </d> +      </b> +    </a>" +      d = REXML::Document.new( source ) +      cs = XPath.match( d, "/descendant-or-self::c" ) +      assert_equal( 4, cs.length ) +      1.upto(4) {|x| assert_equal( x.to_s, cs[x-1].attributes['id'] ) } +    end + +    def test_and +      d = Document.new %q{<doc><route run='*' title='HNO' +      destination='debian_production1' date='*' edition='*' +      source='debian_satellite1'/></doc>} +      assert_equal( nil, d.root.elements["route[@run='0']"] ) +      assert_equal( nil, d.root.elements["route[@run='0' and @title='HNO']"] ) +    end + + +    def test_numbers +      d = Document.new %q{<a x="0" y="*" z="4e" w="e4" v="a"/>} + +      xp1 = "/a[ @x = 0 ]" +      xp2 = "/a[ @x = '0' ]" +      xp3 = "/a[ (@x + 1) = 1 ]" +      xp4 = "/a[ @y = 0 ]" +      xp5 = "/a[ (@z + 1) = 5 ]" +      xp6 = "/a[ (@w + 1) = 5 ]" +      xp7 = "/a[ (@v + 1) = 1 ]" +      xp8 = "/a[ @n = 0 ]" + +      assert_equal( 1, XPath.match( d, xp1 ).length ) +      assert_equal( 1, XPath.match( d, xp2 ).length ) +      assert_equal( 1, XPath.match( d, xp3 ).length ) +      assert_equal( 0, XPath.match( d, xp4 ).length ) +      assert_equal( 0, XPath.match( d, xp5 ).length ) +      assert_equal( 0, XPath.match( d, xp6 ).length ) +      assert_equal( 0, XPath.match( d, xp7 ).length ) +      assert_equal( 0, XPath.match( d, xp8 ).length ) +    end + +    def test_tobis_preceding +      doc_string = '<a> +  <b/> +  <c> +    <d/> +    <e/> +  </c> +</a>' + +      doc = Document.new(doc_string) + +      # e = REXML::XPath.first(doc,'/a/c/e') +      e = doc.root.get_elements('/a/c/e')[0] +      assert_equal( 1, e.get_elements('preceding-sibling::*').length ) +      assert_equal( 2, XPath.match(e, 'preceding::*').length ) +    end + + +    def test_filtering +      #doc=Document.new("<a><b><c1/><c2/></b><b><c3/><c4/></b><b><c5/><c6/></b></a>") +      #assert_equal( 3, XPath.match( doc, '/a/b/*[1]' ).length ) +      #assert_equal( 2, XPath.match( doc, '/a/b/following-sibling::*[1]' ).length ) +    end + +    # Submitted by Alex +    def test_union +      data = %Q{<div id="the_div"> +  <span id="the_span"> +  <strong id="the_strong">a</strong> +  </span> +  <em id="the_em2">b</em> +</div>} +      rd = REXML::Document.new( data ) +      #union = rd.get_elements("/div/span | /div/em") +      #assert_equal(2, union.length, "/div/span | /div/em" ) +      union = rd.get_elements('//*[name()="em" or name()="strong"]') +      assert_equal(2, union.length, 'name() and "or" failed') +      union = rd.get_elements('//em|//strong') +      assert_equal(2, union.length, +             'Both tag types are returned by XPath union operator') +    end + + +    def test_union2 +      src = <<-EOL +<div id="the_div"> +<span id="the_span"> +<strong id="the_strong">a</strong> +</span> +<em id="the_em2">b</em> +</div> +      EOL +      rd = REXML::Document.new( src ) +      union = rd.get_elements('//em|//strong') +      assert_equal(2, union.length, +        'Both tag types are returned by XPath union operator') +    end + + +    def test_a_star_star_one +      string = <<-EOL +<a> +  <b> +    <c1/> +    <d/> +    <e/> +    <f/> +  </b> +  <b> +    <c2/> +    <d/> +    <e/> +    <f/> +  </b> +</a> +      EOL +      d = REXML::Document.new( string ) +      c1 = XPath.match( d, '/a/*/*[1]' ) +      assert_equal( 1, c1.length ) +      assert_equal( 'c1', c1[0].name ) +    end + +    def test_sum +      d = Document.new("<a>"+ +      "<b>1</b><b>2</b><b>3</b>"+ +      "<c><d>1</d><d>2</d></c>"+ +      "<e att='1'/><e att='2'/>"+ +      "</a>") + +      for v,p in [[6, "sum(/a/b)"], +        [9, "sum(//b | //d)"], +        [3, "sum(/a/e/@*)"] ] +        assert_equal( v, XPath::match( d, p ).first ) +      end +    end + +    def test_xpath_namespace +      d = REXML::Document.new("<tag1 xmlns='ns1'><tag2 xmlns='ns2'/><tada>xa</tada></tag1>") +      x = d.root +      num = 0 +      x.each_element('tada') {  num += 1 } +      assert_equal(1, num) +    end + +    def test_ticket_39 +      doc = REXML::Document.new( <<-EOL ) +      <rss> +        <channel> +          <!-- removing the namespace declaration makes the test pass --> +          <convertLineBreaks xmlns="http://www.blogger.com/atom/ns#">true</convertLineBreaks> +          <item> +            <title>Item 1</title> +          </item> +          <item> +            <title>Item 2</title> +            <pubDate>Thu, 13 Oct 2005 19:59:00 +0000</pubDate> +          </item> +          <item> +            <title>Item 3</title> +          </item> +        </channel> +      </rss> +      EOL +      root_node = XPath.first(doc, "rss") +      assert_not_nil root_node +      channel_node = XPath.first(root_node, "channel") +      assert_not_nil channel_node +      items = XPath.match(channel_node, "*") +      assert_equal 4, items.size +      items = XPath.match(channel_node, "item") +      assert_equal 3, items.size  # fails +    end + + +    def test_ticket_42 +      source = "<a></a>" +      doc = Document.new(source) +      bElem = Element.new('b') +      doc.root.add_element(bElem) +      doc.elements.each('//b[name(..) = "a"]') { |x| +        assert_equal x,bElem +      } +    end + +    def test_ticket_56 +      namespaces = {'h' => 'http://www.w3.org/1999/xhtml'} + +      finaldoc = REXML::Document.new(File.read(fixture_path('google.2.xml'))) + +      column_headers = [] + +      REXML::XPath.each(finaldoc, '//h:form[@action="ModifyCampaign"]//h:th', +                        namespaces) do |el| +        node = REXML::XPath.first(el, 'h:a/text()', namespaces) +        column_headers << (node ? node.value : nil) +      end +      column_headers.map! { |h| h.to_s.strip.chomp } +      expected = ["", "", "Current Status", "Current Budget", +        "Clicks", "Impr.", "CTR", "Avg. CPC", "Cost", "Conv. Rate", +        "Cost/Conv."] +      assert_equal( expected, column_headers ) +    end + + +    def test_ticket_70 +      string = <<EOF + +<mydoc> + +    <someelement attribute="1.10">Text1, text, +text</someelement> + +    <someelement attribute="1.11">Text2, text, +text</someelement> + + +</mydoc> + +EOF +      doc = Document.new string +      assert_equal( 1, XPath.match( doc, "//someelement[contains(@attribute,'1.10')]" ).length ) +    end + +    def test_ticket_43 +      #url = http://news.search.yahoo.com/news/rss?p=market&ei=UTF-8&fl=0&x=wrt + +      sum = File.open(fixture_path("yahoo.xml")) do |f| +        Document.new(f).elements.to_a("//item").size +      end +      assert_equal( 10, sum ) + +      text = File.open(fixture_path("yahoo.xml")) do |f| +        Document.new(f).elements.to_a(%Q{//title[contains(text(), "'")]}).collect{|e| e.text}.join +      end +      assert_equal( "Broward labor market's a solid performer (Miami Herald)", text ) +    end + +    def test_ticket_57 +      data = "<?xml version='1.0'?><a:x xmlns:a='1'><a:y p='p' q='q'><a:z>zzz</a:z></a:y></a:x>" + +      r = Document.new(data) + +      assert_equal(Text, REXML::XPath.first(r,"a:x/a:y[@p='p' and @q='q']/a:z/text()").class) +      assert_equal("zzz", REXML::XPath.first(r,"a:x/a:y[@p='p' and @q='q']/a:z/text()").to_s) +    end + +    def test_ticket_59 +      data = "<a> +        <c id='1'/> +        <c id='2'/> +        <b> +          <c id='3'/> +        </b> +        <c id='4'/> +        <b> +          <b> +            <c id='5'/> +          </b> +          <c id='6'/> +        </b> +        <c id='7'/> +        <b> +          <b> +            <c id='8'/> +            <b> +              <c id='9'/> +              <b> +                <c id='10'/> +              </b> +              <c id='11'/> +            </b> +          </b> +        </b> +        <c id='12'/> +      </a>" +      d = Document.new(data) +      res = d.elements.to_a( "//c" ).collect {|e| e.attributes['id'].to_i} +      assert_equal( res, res.sort ) +    end + +    def ticket_61_fixture(doc, xpath) +      matches = [] +      doc.elements.each(xpath) do |element| +        matches << element +        assert_equal('Add', element.text) +        assert_equal('ButtonText', element.attributes['class']) +      end +      assert_equal(1, matches.length) +    end + +    def test_ticket_61_text +      doc = File.open(fixture_path("ticket_61.xml")) do |file| +        REXML::Document.new file +      end +      ticket_61_fixture( doc, "//div[text()='Add' and @class='ButtonText']" ) +    end + +    def test_ticket_61_contains +      doc = File.open(fixture_path("ticket_61.xml")) do |file| +        REXML::Document.new file +      end +      ticket_61_fixture( doc, "//div[contains(.,'Add') and @class='ButtonText']" ) +    end + +    def test_namespaces_0 +      d = Document.new(%q{<x:a xmlns:x="y"/>}) +      assert_equal( 1,  XPath.match( d, "//x:a" ).size ) +      assert_equal( 1,  XPath.match( d, "//x:*" ).size ) +    end + +    def test_ticket_71 +      doc = Document.new(%Q{<root xmlns:ns1="xyz" xmlns:ns2="123"><element ns1:attrname="foo" ns2:attrname="bar"/></root>}) +      el = doc.root.elements[1] +      assert_equal( "element", el.name ) +      el2 = XPath.first( doc.root, "element[@ns:attrname='foo']", { 'ns' => "xyz" } ) +      assert_equal( el, el2 ) +    end + +    def test_ticket_78 +      doc = <<-EOT +      <root> +          <element> +              <tag x='1'>123</tag> +          </element> +          <element> +              <tag x='2'>123a</tag> +          </element> +      </root> +      EOT +      seq = %w{BEGIN 123 END BEGIN 123a END} + +      xmlDoc = Document.new(doc) + +      ["//element[tag='123']/tag", "//element[tag='123a']/tag"].each do |query| +        assert_equal( "BEGIN", seq.shift ) +        XPath.each(xmlDoc, query) { |element| +          assert_equal( seq.shift, element.text ) +        } +        assert_equal( "END", seq.shift ) +      end +    end + +    def test_ticket_79 +      source = "<a><b><c>test</c></b><b><c>3</c></b></a>" +      d = REXML::Document.new( source ) +      r = REXML::XPath.match( d, %q{/a/b[c='test']} ) +      assert_equal(1, r.size()) +      r = REXML::XPath.match( d, %q{/a/b[c='3']} ) +      assert_equal(1, r.size()) +    end + +    def test_or_and +      doc = " +<html> +  <head> +    <title>test</title> +  </head> +  <body> +    <p> +      A <a rel=\"sub\" href=\"/\">link</a>. +    </p> +  </body> +</html> +" + +      xmldoc = REXML::Document.new(doc) +      xpath = "descendant::node()[(local-name()='link' or local-name()='a') and @rel='sub']" +      hrefs = [] +      xmldoc.elements.each(xpath) do |element| +        hrefs << element.attributes["href"] +      end +      assert_equal(["/"], hrefs, "Bug #3842 [ruby-core:32447]") +    end +  end +end diff --git a/jni/ruby/test/rexml/xpath/test_node.rb b/jni/ruby/test/rexml/xpath/test_node.rb new file mode 100644 index 0000000..aec2de1 --- /dev/null +++ b/jni/ruby/test/rexml/xpath/test_node.rb @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- + +require_relative "../rexml_test_utils" + +require "rexml/document" + +module REXMLTests +  class TestXPathNode < Test::Unit::TestCase +    def matches(xml, xpath) +      document = REXML::Document.new(xml) +      REXML::XPath.each(document, xpath).collect(&:to_s) +    end + +    class TestQName < self +      def test_ascii +        xml = <<-XML +<?xml version="1.0" encoding="UTF-8"?> +<root> +  <ascii> +    <child>child</child> +  </ascii> +</root> +        XML +        assert_equal(["<child>child</child>"], +                     matches(xml, "/root/ascii/child")) +      end + +      def test_non_ascii +        xml = <<-XML +<?xml version="1.0" encoding="UTF-8"?> +<root> +  <non-àscii> +    <child>child</child> +  </non-àscii> +</root> +        XML +        assert_equal(["<child>child</child>"], +                     matches(xml, "/root/non-àscii/child")) +      end +    end +  end +end diff --git a/jni/ruby/test/rexml/xpath/test_predicate.rb b/jni/ruby/test/rexml/xpath/test_predicate.rb new file mode 100644 index 0000000..287e131 --- /dev/null +++ b/jni/ruby/test/rexml/xpath/test_predicate.rb @@ -0,0 +1,82 @@ +require "test/unit/testcase" +require "rexml/document" +require "rexml/xpath" +require "rexml/parsers/xpathparser" + +module REXMLTests +  class TestXPathPredicate < Test::Unit::TestCase +    include REXML +    SRC=<<-EOL +    <article> +       <section role="subdivision" id="1"> +          <para>free flowing text.</para> +       </section> +       <section role="division"> +          <section role="subdivision" id="2"> +             <para>free flowing text.</para> +          </section> +          <section role="division"> +             <para>free flowing text.</para> +          </section> +       </section> +    </article> +    EOL + +    def setup +      @doc = REXML::Document.new( SRC ) +      @parser = REXML::Parsers::XPathParser.new + +    end + +    def test_predicates_parent +      path = '//section[../self::section[@role="division"]]' +      m = do_path( path ) +      assert_equal( 2, m.size ) +      assert_equal( "2", m[0].attributes["id"] ) +      assert_nil( m[1].attributes["id"] ) +    end + +    def test_predicates_single +      path = '//section[@role="subdivision" and not(../self::section[@role="division"])]' +      m = do_path( path ) +      assert_equal( 1, m.size ) +      assert_equal( "1", m[0].attributes["id"] ) +    end + +    def test_predicates_multi +      path = '//section[@role="subdivision"][not(../self::section[@role="division"])]' +      m = do_path( path ) +      assert_equal( 1, m.size ) +      assert_equal( "1", m[0].attributes["id"] ) +    end + +    def do_path( path ) +      m = REXML::XPath.match( @doc, path ) +      #puts path, @parser.parse( path ).inspect +      return m +    end + +    def test_get_no_siblings_terminal_nodes +      source = <<-XML +<a> +  <b number='1' str='abc'>TEXT1</b> +  <c number='1'/> +  <c number='2' str='def'> +    <b number='3'/> +    <d number='1' str='abc'>TEXT2</d> +    <b number='2'><!--COMMENT--></b> +  </c> +</a> +XML +      doc = REXML::Document.new(source) +      predicate = "count(child::node()|" + +                        "following-sibling::node()|" + +                        "preceding-sibling::node())=0" +      m = REXML::XPath.match(doc, "/descendant-or-self::node()[#{predicate}]") +      assert_equal( [REXML::Text.new("TEXT1"), +                     REXML::Text.new("TEXT2"), +                     REXML::Comment.new("COMMENT")], +                    m ) +    end +  end +end diff --git a/jni/ruby/test/rexml/xpath/test_text.rb b/jni/ruby/test/rexml/xpath/test_text.rb new file mode 100644 index 0000000..46aba3c --- /dev/null +++ b/jni/ruby/test/rexml/xpath/test_text.rb @@ -0,0 +1,74 @@ +require 'test/unit' +require 'rexml/document' +require 'rexml/element' +require 'rexml/xpath' + +module REXMLTests +  class TestXPathText < Test::Unit::TestCase +    def setup +      @doc = REXML::Document.new +    end + +    def tear_down +    end + +    def test_text_as_element +      node1 = REXML::Element.new('a', @doc) +      node2 = REXML::Element.new('b', node1) +      REXML::Text.new('test', false, node2) +      assert_equal(1, @doc.elements.size, "doc owns 1 element node1") +      assert_same(node1, @doc.elements[1], "doc owns 1 element node1") +      assert_equal(1, node1.elements.size, "node1 owns 1 element node2") +      assert_same(node2, node1.elements[1], "node1 owns 1 element node2") +      assert_equal(1, node2.size, "node2 owns 1 text element") +    end + +    def test_text_in_xpath_query +      node1 = REXML::Element.new('a', @doc) +      node2 = REXML::Element.new('b', node1) +      textnode = REXML::Text.new('test', false, node2) +      textnode.parent = node2   # should be unnecessary +      nodes = @doc.get_elements('//b') +      assert_equal(1, nodes.size, "document has one element") +      # why doesn't this query work right? +      nodes = REXML::XPath.match(@doc, '//text()') +      assert_equal(1, nodes.size, "//text() should yield one Text element") +      assert_equal(REXML::Text, nodes[0].class) +    end + +    def test_comment_in_xpath_query +      node1 = REXML::Element.new('a', @doc) +      node2 = REXML::Element.new('b', node1) +      commentnode = REXML::Comment.new('test', node2) +      nodes = REXML::XPath.match(@doc, '//comment()') +      assert_equal(1, nodes.size, "//comment() should yield one Comment element") +      assert_same commentnode, nodes[0] +    end + +    def test_parentage +      node1 = REXML::Element.new('a', @doc) +      assert_same(@doc, node1.parent, "node1 parent is document") +      node2 = REXML::Element.new('b', node1) +      assert_same(node1, node2.parent, "node2 parent is node1") +      textnode = REXML::Text.new('test', false, node2) +      # why isn't the text's parent node2? +      # Also look at Comment, etc. +      assert_same(node2, textnode.parent) +      comment = REXML::Comment.new('Test comment', node2) +      assert_same(node2, comment.parent) +    end + +    def test_ancestors +      node1 = REXML::Element.new('a', @doc) +      node2 = REXML::Element.new('b', node1) +      textnode = REXML::Text.new('test', false, node2) +      #textnode.parent = node2   # should be unnecessary +      assert_same node2, textnode.parent +      nodes = @doc.get_elements('//b/ancestor::*') +      assert_equal(1, nodes.size, "<b> has one element ancestor") +      nodes = @doc.get_elements('//b/ancestor::node()') +      assert_equal(2, nodes.size, "<b> has two node ancestors") +      assert nodes[1].kind_of?(REXML::Document) +    end +  end +end | 
