2015-12-16 00:07:31 -05:00
|
|
|
# frozen_string_literal: false
|
2010-09-17 09:14:14 -04:00
|
|
|
require "test/unit/testcase"
|
|
|
|
|
|
|
|
require "rexml/document"
|
|
|
|
|
2019-05-25 04:58:49 -04:00
|
|
|
# TODO: Split me
|
2014-05-27 08:07:40 -04:00
|
|
|
module REXMLTests
|
2014-05-27 09:10:55 -04:00
|
|
|
class FunctionsTester < Test::Unit::TestCase
|
|
|
|
include REXML
|
2019-02-09 15:33:06 -05:00
|
|
|
|
|
|
|
def setup
|
|
|
|
super
|
|
|
|
REXML::Functions.context = nil
|
|
|
|
end
|
|
|
|
|
2014-05-27 09:10:55 -04:00
|
|
|
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
|
2010-09-17 09:46:56 -04:00
|
|
|
|
2014-05-27 09:10:55 -04:00
|
|
|
# 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
|
2010-09-17 09:14:14 -04:00
|
|
|
|
2014-05-27 09:10:55 -04:00
|
|
|
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
|
2010-09-17 09:46:56 -04:00
|
|
|
|
2014-05-27 09:10:55 -04:00
|
|
|
# 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 { |test|
|
|
|
|
search, expected = test
|
|
|
|
set = doc.elements.to_a("//a[contains(@href, '#{search}')]")
|
|
|
|
assert_equal expected, set.size
|
|
|
|
}
|
|
|
|
end
|
2010-09-17 09:46:56 -04:00
|
|
|
|
2014-05-27 09:10:55 -04:00
|
|
|
# Mike Stok and Sean Russell
|
|
|
|
def test_substring
|
|
|
|
# examples from http://www.w3.org/TR/xpath#function-substring
|
|
|
|
doc = Document.new('<test string="12345" />')
|
|
|
|
|
|
|
|
#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
|
2010-09-17 09:14:14 -04:00
|
|
|
|
2014-05-27 09:10:55 -04:00
|
|
|
def test_substring_angrez
|
|
|
|
testString = REXML::Functions::substring_after("helloworld","hello")
|
|
|
|
assert_equal( 'world', testString )
|
|
|
|
end
|
2010-09-17 09:14:14 -04:00
|
|
|
|
2014-05-27 09:10:55 -04:00
|
|
|
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
|
2010-09-17 09:46:56 -04:00
|
|
|
|
2014-05-27 09:10:55 -04:00
|
|
|
def test_name
|
|
|
|
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
|
2010-09-17 09:46:56 -04:00
|
|
|
|
2014-05-27 09:10:55 -04:00
|
|
|
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
|
2010-09-17 09:46:56 -04:00
|
|
|
|
2014-05-27 09:10:55 -04:00
|
|
|
def test_substring2
|
|
|
|
doc = Document.new('<test string="12345" />')
|
|
|
|
assert_equal(1,doc.elements.to_a("//test[substring(@string,2)='2345']").size)
|
|
|
|
end
|
2010-09-17 09:46:56 -04:00
|
|
|
|
2014-05-27 09:10:55 -04:00
|
|
|
# Submitted by Kouhei
|
|
|
|
def test_floor_ceiling_round
|
|
|
|
source = "<a><b id='1'/><b id='2'/><b id='3'/></a>"
|
|
|
|
doc = REXML::Document.new(source)
|
|
|
|
|
|
|
|
id_1 = doc.elements["/a/b[@id='1']"]
|
|
|
|
id_2 = doc.elements["/a/b[@id='2']"]
|
|
|
|
id_3 = doc.elements["/a/b[@id='3']"]
|
|
|
|
|
|
|
|
good = {
|
|
|
|
"floor" => [[], [id_1], [id_2], [id_3]],
|
|
|
|
"ceiling" => [[id_1], [id_2], [id_3], []],
|
|
|
|
"round" => [[id_1], [id_2], [id_3], []]
|
|
|
|
}
|
|
|
|
good.each do |key, value|
|
|
|
|
(0..3).each do |i|
|
|
|
|
xpath = "//b[number(@id) = #{key}(#{i+0.5})]"
|
|
|
|
assert_equal(value[i], REXML::XPath.match(doc, xpath))
|
|
|
|
end
|
2010-09-17 09:46:56 -04:00
|
|
|
end
|
|
|
|
|
2014-05-27 09:10:55 -04:00
|
|
|
good["round"] = [[], [id_1], [id_2], [id_3]]
|
|
|
|
good.each do |key, value|
|
|
|
|
(0..3).each do |i|
|
|
|
|
xpath = "//b[number(@id) = #{key}(#{i+0.4})]"
|
|
|
|
assert_equal(value[i], REXML::XPath.match(doc, xpath))
|
|
|
|
end
|
2010-09-17 09:46:56 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2014-05-27 09:10:55 -04:00
|
|
|
# Submitted by Kou
|
|
|
|
def test_lang
|
|
|
|
d = Document.new(<<-XML)
|
|
|
|
<a xml:lang="en">
|
|
|
|
<b xml:lang="ja">
|
|
|
|
<c xml:lang="fr"/>
|
|
|
|
<d/>
|
|
|
|
<e xml:lang="ja-JP"/>
|
|
|
|
<f xml:lang="en-US"/>
|
|
|
|
</b>
|
|
|
|
</a>
|
|
|
|
XML
|
|
|
|
|
|
|
|
assert_equal(1, d.elements.to_a("//*[lang('fr')]").size)
|
|
|
|
assert_equal(3, d.elements.to_a("//*[lang('ja')]").size)
|
|
|
|
assert_equal(2, d.elements.to_a("//*[lang('en')]").size)
|
|
|
|
assert_equal(1, d.elements.to_a("//*[lang('en-us')]").size)
|
|
|
|
|
|
|
|
d = Document.new(<<-XML)
|
|
|
|
<root>
|
|
|
|
<para xml:lang="en"/>
|
|
|
|
<div xml:lang="en"><para/></div>
|
|
|
|
<para xml:lang="EN"/>
|
|
|
|
<para xml:lang="en-us"/>
|
|
|
|
</root>
|
|
|
|
XML
|
|
|
|
|
|
|
|
assert_equal(5, d.elements.to_a("//*[lang('en')]").size)
|
|
|
|
end
|
2010-09-17 09:14:14 -04:00
|
|
|
|
2014-05-27 09:10:55 -04:00
|
|
|
def test_ticket_60
|
|
|
|
document = REXML::Document.new("<a><b>A</b><b>1</b></a>")
|
|
|
|
assert_equal( "A", REXML::XPath.first(document, '//b[.="A"]').text )
|
|
|
|
assert_equal( "1", REXML::XPath.first(document, '//b[.="1"]').text )
|
|
|
|
end
|
2010-09-17 09:14:14 -04:00
|
|
|
|
2014-05-27 09:10:55 -04:00
|
|
|
def test_normalize_space
|
|
|
|
source = "<a><!--COMMENT A--><b><!-- COMMENT A --></b></a>"
|
|
|
|
doc = REXML::Document.new(source)
|
|
|
|
predicate = "string(.)=normalize_space('\nCOMMENT \n A \n\n ')"
|
|
|
|
m = REXML::XPath.match(doc, "//comment()[#{predicate}]")
|
|
|
|
assert_equal( [REXML::Comment.new("COMMENT A")], m )
|
|
|
|
end
|
2017-08-13 08:14:24 -04:00
|
|
|
|
2019-02-09 15:33:06 -05:00
|
|
|
def test_string_nil_without_context
|
|
|
|
doc = REXML::Document.new(<<-XML)
|
|
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
|
|
<root>
|
|
|
|
<foo bar="baz"/>
|
|
|
|
<foo bar=""/>
|
|
|
|
</root>
|
|
|
|
XML
|
|
|
|
|
2019-02-09 15:37:28 -05:00
|
|
|
assert_equal([doc.root.elements[2]],
|
|
|
|
REXML::XPath.match(doc,
|
|
|
|
"//foo[@bar=$n]",
|
|
|
|
nil,
|
|
|
|
{"n" => nil}))
|
2019-02-09 15:33:06 -05:00
|
|
|
end
|
|
|
|
|
2017-08-13 08:14:24 -04:00
|
|
|
def test_unregistered_method
|
|
|
|
doc = Document.new("<root/>")
|
|
|
|
assert_nil(XPath::first(doc.root, "to_s()"))
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_nonexistent_function
|
|
|
|
doc = Document.new("<root><nonexistent/></root>")
|
|
|
|
# TODO: Maybe, this is not XPath spec behavior.
|
|
|
|
# This behavior must be reconsidered.
|
|
|
|
assert_equal(doc.root.elements[1],
|
|
|
|
XPath::first(doc.root, "nonexistent()"))
|
|
|
|
end
|
2010-09-17 09:14:14 -04:00
|
|
|
end
|
|
|
|
end
|