From 643344dc9460626617c9ce88f07b3ae0fed49150 Mon Sep 17 00:00:00 2001 From: Kouhei Sutou Date: Sat, 25 May 2019 17:58:49 +0900 Subject: [ruby/rexml] xpath local_name: fix a bug that nil is returned for nonexistent case It must be an empty string. https://github.com/ruby/rexml/commit/81bc7cd4f5 --- test/rexml/functions/test_base.rb | 261 ++++++++++++++++++++++++++++++++ test/rexml/functions/test_boolean.rb | 75 +++++++++ test/rexml/functions/test_local_name.rb | 44 ++++++ test/rexml/functions/test_number.rb | 35 +++++ test/rexml/test_functions.rb | 260 ------------------------------- test/rexml/test_functions_boolean.rb | 75 --------- test/rexml/test_functions_number.rb | 35 ----- 7 files changed, 415 insertions(+), 370 deletions(-) create mode 100644 test/rexml/functions/test_base.rb create mode 100644 test/rexml/functions/test_boolean.rb create mode 100644 test/rexml/functions/test_local_name.rb create mode 100644 test/rexml/functions/test_number.rb delete mode 100644 test/rexml/test_functions.rb delete mode 100644 test/rexml/test_functions_boolean.rb delete mode 100644 test/rexml/test_functions_number.rb (limited to 'test') diff --git a/test/rexml/functions/test_base.rb b/test/rexml/functions/test_base.rb new file mode 100644 index 0000000000..74dc1a31de --- /dev/null +++ b/test/rexml/functions/test_base.rb @@ -0,0 +1,261 @@ +# frozen_string_literal: false +require "test/unit/testcase" + +require "rexml/document" + +# TODO: Split me +module REXMLTests + class FunctionsTester < Test::Unit::TestCase + include REXML + + def setup + super + REXML::Functions.context = nil + end + + def test_functions + # trivial text() test + # confuse-a-function + source = "more dumb text" + 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 + + # Contributed by Mike Stok + def test_starts_with + source = <<-EOF + + a@b.c + http://www.foo.com + + 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_string_length + doc = Document.new <<-EOF + + + + + + + + + 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 + + a@b.c + http://www.foo.com + + 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 + + # Mike Stok and Sean Russell + def test_substring + # examples from http://www.w3.org/TR/xpath#function-substring + doc = Document.new('') + + #puts XPath.first(d, 'node()[0 + 1]') + #d = Document.new("") + #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_substring_angrez + testString = REXML::Functions::substring_after("helloworld","hello") + assert_equal( 'world', testString ) + end + + def test_translate + source = <<-EOF + + + + + + + + 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_name + d = REXML::Document.new("") + 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("") + 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_substring2 + doc = Document.new('') + assert_equal(1,doc.elements.to_a("//test[substring(@string,2)='2345']").size) + end + + # Submitted by Kouhei + def test_floor_ceiling_round + source = "" + 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 + end + + 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 + end + end + + # Submitted by Kou + def test_lang + d = Document.new(<<-XML) + + + + + + + + + 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) + + +
+ + +
+ XML + + assert_equal(5, d.elements.to_a("//*[lang('en')]").size) + end + + def test_ticket_60 + document = REXML::Document.new("A1") + assert_equal( "A", REXML::XPath.first(document, '//b[.="A"]').text ) + assert_equal( "1", REXML::XPath.first(document, '//b[.="1"]').text ) + end + + def test_normalize_space + source = "" + 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 + + def test_string_nil_without_context + doc = REXML::Document.new(<<-XML) + + + + + + XML + + assert_equal([doc.root.elements[2]], + REXML::XPath.match(doc, + "//foo[@bar=$n]", + nil, + {"n" => nil})) + end + + def test_unregistered_method + doc = Document.new("") + assert_nil(XPath::first(doc.root, "to_s()")) + end + + def test_nonexistent_function + doc = Document.new("") + # 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 + end +end diff --git a/test/rexml/functions/test_boolean.rb b/test/rexml/functions/test_boolean.rb new file mode 100644 index 0000000000..b3e2117c10 --- /dev/null +++ b/test/rexml/functions/test_boolean.rb @@ -0,0 +1,75 @@ +# frozen_string_literal: false + +require "test/unit" +require "rexml/document" +require "rexml/functions" + +module REXMLTests + class TestFunctionsBoolean < Test::Unit::TestCase + def setup + REXML::Functions.context = nil + end + + def test_true + assert_equal(true, REXML::Functions.boolean(true)) + end + + def test_false + assert_equal(false, REXML::Functions.boolean(false)) + end + + def test_integer_true + assert_equal(true, REXML::Functions.boolean(1)) + end + + def test_integer_positive_zero + assert_equal(false, REXML::Functions.boolean(0)) + end + + def test_integer_negative_zero + assert_equal(false, REXML::Functions.boolean(-0)) + end + + def test_float_true + assert_equal(true, REXML::Functions.boolean(1.1)) + end + + def test_float_positive_zero + assert_equal(false, REXML::Functions.boolean(-0.0)) + end + + def test_float_negative_zero + assert_equal(false, REXML::Functions.boolean(-0.0)) + end + + def test_float_nan + assert_equal(false, REXML::Functions.boolean(Float::NAN)) + end + + def test_string_true + assert_equal(true, REXML::Functions.boolean("content")) + end + + def test_string_empty + assert_equal(false, REXML::Functions.boolean("")) + end + + def test_node_set_true + root = REXML::Document.new("").root + assert_equal(true, REXML::Functions.boolean([root])) + end + + def test_node_set_empty + assert_equal(false, REXML::Functions.boolean([])) + end + + def test_nil + assert_equal(false, REXML::Functions.boolean(nil)) + end + + def test_context + REXML::Functions.context = {node: true} + assert_equal(true, REXML::Functions.boolean()) + end + end +end diff --git a/test/rexml/functions/test_local_name.rb b/test/rexml/functions/test_local_name.rb new file mode 100644 index 0000000000..97c9e74852 --- /dev/null +++ b/test/rexml/functions/test_local_name.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: false + +require "test/unit" +require "rexml/document" +require "rexml/functions" + +module REXMLTests + class TestFunctionsLocalName < Test::Unit::TestCase + def setup + REXML::Functions.context = nil + end + + def test_one + document = REXML::Document.new(<<-XML) + + + + XML + node_set = document.root.children + assert_equal("child", REXML::Functions.local_name(node_set)) + end + + def test_multiple + document = REXML::Document.new(<<-XML) + + + + + XML + node_set = document.root.children + assert_equal("child1", REXML::Functions.local_name(node_set)) + end + + def test_nonexistent + assert_equal("", REXML::Functions.local_name([])) + end + + def test_context + document = REXML::Document.new("") + REXML::Functions.context = {node: document.root} + assert_equal("root", REXML::Functions.local_name()) + end + end +end diff --git a/test/rexml/functions/test_number.rb b/test/rexml/functions/test_number.rb new file mode 100644 index 0000000000..84ec5c7ba7 --- /dev/null +++ b/test/rexml/functions/test_number.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: false +require 'rexml/document' +require 'test/unit' +require 'rexml/functions' + +module REXMLTests + class TC_Rexml_Functions_Number < Test::Unit::TestCase + + def test_functions_number_int + telem = REXML::Element.new("elem") + telem.text="9" + assert_equal(9, REXML::Functions::number(telem)) + end + def test_functions_number_float + telem = REXML::Element.new("elem") + telem.text="10.4" + assert_equal(10.4, REXML::Functions::number(telem)) + end + def test_functions_number_negative_int + telem = REXML::Element.new("elem") + telem.text="-9" + assert_equal(-9, REXML::Functions::number(telem)) + end + def test_functions_number_negative_float + telem = REXML::Element.new("elem") + telem.text="-9.13" + assert_equal(-9.13, REXML::Functions::number(telem)) + end + #def test_functions_number_scientific_notation + # telem = REXML::Element.new("elem") + # telem.text="9.13E12" + # assert_equal(9.13E12, REXML::Functions::number(telem)) + #end + end +end diff --git a/test/rexml/test_functions.rb b/test/rexml/test_functions.rb deleted file mode 100644 index a00b25b2c1..0000000000 --- a/test/rexml/test_functions.rb +++ /dev/null @@ -1,260 +0,0 @@ -# frozen_string_literal: false -require "test/unit/testcase" - -require "rexml/document" - -module REXMLTests - class FunctionsTester < Test::Unit::TestCase - include REXML - - def setup - super - REXML::Functions.context = nil - end - - def test_functions - # trivial text() test - # confuse-a-function - source = "more dumb text" - 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 - - # Contributed by Mike Stok - def test_starts_with - source = <<-EOF - - a@b.c - http://www.foo.com - - 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_string_length - doc = Document.new <<-EOF - - - - - - - - - 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 - - a@b.c - http://www.foo.com - - 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 - - # Mike Stok and Sean Russell - def test_substring - # examples from http://www.w3.org/TR/xpath#function-substring - doc = Document.new('') - - #puts XPath.first(d, 'node()[0 + 1]') - #d = Document.new("") - #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_substring_angrez - testString = REXML::Functions::substring_after("helloworld","hello") - assert_equal( 'world', testString ) - end - - def test_translate - source = <<-EOF - - - - - - - - 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_name - d = REXML::Document.new("") - 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("") - 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_substring2 - doc = Document.new('') - assert_equal(1,doc.elements.to_a("//test[substring(@string,2)='2345']").size) - end - - # Submitted by Kouhei - def test_floor_ceiling_round - source = "" - 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 - end - - 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 - end - end - - # Submitted by Kou - def test_lang - d = Document.new(<<-XML) - - - - - - - - - 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) - - -
- - -
- XML - - assert_equal(5, d.elements.to_a("//*[lang('en')]").size) - end - - def test_ticket_60 - document = REXML::Document.new("A1") - assert_equal( "A", REXML::XPath.first(document, '//b[.="A"]').text ) - assert_equal( "1", REXML::XPath.first(document, '//b[.="1"]').text ) - end - - def test_normalize_space - source = "" - 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 - - def test_string_nil_without_context - doc = REXML::Document.new(<<-XML) - - - - - - XML - - assert_equal([doc.root.elements[2]], - REXML::XPath.match(doc, - "//foo[@bar=$n]", - nil, - {"n" => nil})) - end - - def test_unregistered_method - doc = Document.new("") - assert_nil(XPath::first(doc.root, "to_s()")) - end - - def test_nonexistent_function - doc = Document.new("") - # 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 - end -end diff --git a/test/rexml/test_functions_boolean.rb b/test/rexml/test_functions_boolean.rb deleted file mode 100644 index b3e2117c10..0000000000 --- a/test/rexml/test_functions_boolean.rb +++ /dev/null @@ -1,75 +0,0 @@ -# frozen_string_literal: false - -require "test/unit" -require "rexml/document" -require "rexml/functions" - -module REXMLTests - class TestFunctionsBoolean < Test::Unit::TestCase - def setup - REXML::Functions.context = nil - end - - def test_true - assert_equal(true, REXML::Functions.boolean(true)) - end - - def test_false - assert_equal(false, REXML::Functions.boolean(false)) - end - - def test_integer_true - assert_equal(true, REXML::Functions.boolean(1)) - end - - def test_integer_positive_zero - assert_equal(false, REXML::Functions.boolean(0)) - end - - def test_integer_negative_zero - assert_equal(false, REXML::Functions.boolean(-0)) - end - - def test_float_true - assert_equal(true, REXML::Functions.boolean(1.1)) - end - - def test_float_positive_zero - assert_equal(false, REXML::Functions.boolean(-0.0)) - end - - def test_float_negative_zero - assert_equal(false, REXML::Functions.boolean(-0.0)) - end - - def test_float_nan - assert_equal(false, REXML::Functions.boolean(Float::NAN)) - end - - def test_string_true - assert_equal(true, REXML::Functions.boolean("content")) - end - - def test_string_empty - assert_equal(false, REXML::Functions.boolean("")) - end - - def test_node_set_true - root = REXML::Document.new("").root - assert_equal(true, REXML::Functions.boolean([root])) - end - - def test_node_set_empty - assert_equal(false, REXML::Functions.boolean([])) - end - - def test_nil - assert_equal(false, REXML::Functions.boolean(nil)) - end - - def test_context - REXML::Functions.context = {node: true} - assert_equal(true, REXML::Functions.boolean()) - end - end -end diff --git a/test/rexml/test_functions_number.rb b/test/rexml/test_functions_number.rb deleted file mode 100644 index 84ec5c7ba7..0000000000 --- a/test/rexml/test_functions_number.rb +++ /dev/null @@ -1,35 +0,0 @@ -# frozen_string_literal: false -require 'rexml/document' -require 'test/unit' -require 'rexml/functions' - -module REXMLTests - class TC_Rexml_Functions_Number < Test::Unit::TestCase - - def test_functions_number_int - telem = REXML::Element.new("elem") - telem.text="9" - assert_equal(9, REXML::Functions::number(telem)) - end - def test_functions_number_float - telem = REXML::Element.new("elem") - telem.text="10.4" - assert_equal(10.4, REXML::Functions::number(telem)) - end - def test_functions_number_negative_int - telem = REXML::Element.new("elem") - telem.text="-9" - assert_equal(-9, REXML::Functions::number(telem)) - end - def test_functions_number_negative_float - telem = REXML::Element.new("elem") - telem.text="-9.13" - assert_equal(-9.13, REXML::Functions::number(telem)) - end - #def test_functions_number_scientific_notation - # telem = REXML::Element.new("elem") - # telem.text="9.13E12" - # assert_equal(9.13E12, REXML::Functions::number(telem)) - #end - end -end -- cgit v1.2.3