1require "test/unit/testcase" 2 3require "rexml/document" 4 5class FunctionsTester < Test::Unit::TestCase 6 include REXML 7 def test_functions 8 # trivial text() test 9 # confuse-a-function 10 source = "<a>more <b id='1'/><b id='2'>dumb</b><b id='3'/><c/> text</a>" 11 doc = Document.new source 12 res = "" 13 XPath::each(doc.root, "text()") {|val| res << val.to_s} 14 assert_equal "more text", res 15 16 res = XPath::first(doc.root, "b[last()]") 17 assert_equal '3', res.attributes['id'] 18 res = XPath::first(doc.root, "b[position()=2]") 19 assert_equal '2', res.attributes['id'] 20 res = XPath::first(doc.root, "*[name()='c']") 21 assert_equal "c", res.name 22 end 23 24 # Contributed by Mike Stok 25 def test_starts_with 26 source = <<-EOF 27 <foo> 28 <a href="mailto:a@b.c">a@b.c</a> 29 <a href="http://www.foo.com">http://www.foo.com</a> 30 </foo> 31 EOF 32 doc = Document.new source 33 mailtos = doc.elements.to_a("//a[starts-with(@href, 'mailto:')]") 34 assert_equal 1, mailtos.size 35 assert_equal "mailto:a@b.c", mailtos[0].attributes['href'] 36 37 ailtos = doc.elements.to_a("//a[starts-with(@href, 'ailto:')]") 38 assert_equal 0, ailtos.size 39 end 40 41 def test_string_length 42 doc = Document.new <<-EOF 43 <AAA> 44 <Q/> 45 <SSSS/> 46 <BB/> 47 <CCC/> 48 <DDDDDDDD/> 49 <EEEE/> 50 </AAA> 51 EOF 52 assert doc, "create doc" 53 54 set = doc.elements.to_a("//*[string-length(name()) = 3]") 55 assert_equal 2, set.size, "nodes with names length = 3" 56 57 set = doc.elements.to_a("//*[string-length(name()) < 3]") 58 assert_equal 2, set.size, "nodes with names length < 3" 59 60 set = doc.elements.to_a("//*[string-length(name()) > 3]") 61 assert_equal 3, set.size, "nodes with names length > 3" 62 end 63 64 # Test provided by Mike Stok 65 def test_contains 66 source = <<-EOF 67 <foo> 68 <a href="mailto:a@b.c">a@b.c</a> 69 <a href="http://www.foo.com">http://www.foo.com</a> 70 </foo> 71 EOF 72 doc = Document.new source 73 74 [['o', 2], ['foo', 1], ['bar', 0]].each { |test| 75 search, expected = test 76 set = doc.elements.to_a("//a[contains(@href, '#{search}')]") 77 assert_equal expected, set.size 78 } 79 end 80 81 # Mike Stok and Sean Russell 82 def test_substring 83 # examples from http://www.w3.org/TR/xpath#function-substring 84 doc = Document.new('<test string="12345" />') 85 86 d = Document.new("<a b='1'/>") 87 #puts XPath.first(d, 'node()[0 + 1]') 88 #d = Document.new("<a b='1'/>") 89 #puts XPath.first(d, 'a[0 mod 0]') 90 [ [1.5, 2.6, '234'], 91 [0, 3, '12'], 92 [0, '0 div 0', ''], 93 [1, '0 div 0', ''], 94 ['-42', '1 div 0', '12345'], 95 ['-1 div 0', '1 div 0', ''] 96 ].each { |start, length, expected| 97 set = doc.elements.to_a("//test[substring(@string, #{start}, #{length}) = '#{expected}']") 98 assert_equal 1, set.size, "#{start}, #{length}, '#{expected}'" 99 } 100 end 101 102 def test_substring_angrez 103 testString = REXML::Functions::substring_after("helloworld","hello") 104 assert_equal( 'world', testString ) 105 end 106 107 def test_translate 108 source = <<-EOF 109 <doc> 110 <case name='w3c one' result='BAr' /> <!-- w3c --> 111 <case name='w3c two' result='AAA' /> <!-- w3c --> 112 <case name='alchemy' result="gold" /> <!-- mike --> 113 <case name='vbxml one' result='A Space Odyssey' /> 114 <case name='vbxml two' result='AbCdEf' /> 115 </doc> 116 EOF 117 118 doc = Document.new(source) 119 120 [ ['bar', 'abc', 'ABC', 'w3c one'], 121 ['--aaa--','abc-','ABC', 'w3c two'], 122 ['lead', 'dear language', 'doll groover', 'alchemy'], 123 ['A Space Odissei', 'i', 'y', 'vbxml one'], 124 ['abcdefg', 'aceg', 'ACE', 'vbxml two'], 125 ].each { |arg1, arg2, arg3, name| 126 translate = "translate('#{arg1}', '#{arg2}', '#{arg3}')" 127 set = doc.elements.to_a("//case[@result = #{translate}]") 128 assert_equal 1, set.size, translate 129 assert_equal name, set[0].attributes['name'] 130 } 131 end 132 133 def test_name 134 d = REXML::Document.new("<a xmlns:x='foo'><b/><x:b/></a>") 135 assert_equal 1, d.root.elements.to_a('*[name() = "b"]').size 136 assert_equal 1, d.elements.to_a('//*[name() = "x:b"]').size 137 end 138 139 def test_local_name 140 d = REXML::Document.new("<a xmlns:x='foo'><b/><x:b/></a>") 141 assert_equal 2, d.root.elements.to_a('*[local_name() = "b"]').size 142 assert_equal 2, d.elements.to_a('//*[local_name() = "b"]').size 143 end 144 145 def test_substring2 146 doc = Document.new('<test string="12345" />') 147 assert_equal(1,doc.elements.to_a("//test[substring(@string,2)='2345']").size) 148 end 149 150 # Submitted by Kouhei 151 def test_floor_ceiling_round 152 source = "<a><b id='1'/><b id='2'/><b id='3'/></a>" 153 doc = REXML::Document.new(source) 154 155 id_1 = doc.elements["/a/b[@id='1']"] 156 id_2 = doc.elements["/a/b[@id='2']"] 157 id_3 = doc.elements["/a/b[@id='3']"] 158 159 good = { 160 "floor" => [[], [id_1], [id_2], [id_3]], 161 "ceiling" => [[id_1], [id_2], [id_3], []], 162 "round" => [[id_1], [id_2], [id_3], []] 163 } 164 good.each do |key, value| 165 (0..3).each do |i| 166 xpath = "//b[number(@id) = #{key}(#{i+0.5})]" 167 assert_equal(value[i], REXML::XPath.match(doc, xpath)) 168 end 169 end 170 171 good["round"] = [[], [id_1], [id_2], [id_3]] 172 good.each do |key, value| 173 (0..3).each do |i| 174 xpath = "//b[number(@id) = #{key}(#{i+0.4})]" 175 assert_equal(value[i], REXML::XPath.match(doc, xpath)) 176 end 177 end 178 end 179 180 # Submitted by Kou 181 def test_lang 182 d = Document.new(<<-XML) 183 <a xml:lang="en"> 184 <b xml:lang="ja"> 185 <c xml:lang="fr"/> 186 <d/> 187 <e xml:lang="ja-JP"/> 188 <f xml:lang="en-US"/> 189 </b> 190 </a> 191 XML 192 193 assert_equal(1, d.elements.to_a("//*[lang('fr')]").size) 194 assert_equal(3, d.elements.to_a("//*[lang('ja')]").size) 195 assert_equal(2, d.elements.to_a("//*[lang('en')]").size) 196 assert_equal(1, d.elements.to_a("//*[lang('en-us')]").size) 197 198 d = Document.new(<<-XML) 199 <root> 200 <para xml:lang="en"/> 201 <div xml:lang="en"><para/></div> 202 <para xml:lang="EN"/> 203 <para xml:lang="en-us"/> 204 </root> 205 XML 206 207 assert_equal(5, d.elements.to_a("//*[lang('en')]").size) 208 end 209 210 def test_ticket_60 211 document = REXML::Document.new("<a><b>A</b><b>1</b></a>") 212 assert_equal( "A", REXML::XPath.first(document, '//b[.="A"]').text ) 213 assert_equal( "1", REXML::XPath.first(document, '//b[.="1"]').text ) 214 end 215 216 def test_normalize_space 217 source = "<a><!--COMMENT A--><b><!-- COMMENT A --></b></a>" 218 doc = REXML::Document.new(source) 219 predicate = "string(.)=normalize_space('\nCOMMENT \n A \n\n ')" 220 m = REXML::XPath.match(doc, "//comment()[#{predicate}]") 221 assert_equal( [REXML::Comment.new("COMMENT A")], m ) 222 end 223end 224