diff --git a/CHANGELOG.md b/CHANGELOG.md index 4661cf2598..76f2586be3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,11 @@ Nokogiri follows [Semantic Versioning](https://semver.org/), please see the [REA * [JRuby] `{XML,HTML}::Document.parse` now invokes `#initialize` exactly once. Previously `#initialize` was not called, which was a problem for subclassing such as done by `Loofah`. +### Improved + +* [JRuby] Update the algorithm used to calculate `Node#line` to be wrong less-often. The underlying parser, Xerces, does not track line numbers, and so we've always used a hacky solution for this method. [[#1223](https://github.com/sparklemotion/nokogiri/issues/1223)] + + ## v1.11.1 / 2021-01-06 ### Fixed diff --git a/ext/java/nokogiri/XmlNode.java b/ext/java/nokogiri/XmlNode.java index cfbea83dfa..790b849ec2 100644 --- a/ext/java/nokogiri/XmlNode.java +++ b/ext/java/nokogiri/XmlNode.java @@ -1406,14 +1406,22 @@ private boolean count(Node node, int[] counter) { if (node == this.node) { return true; } + NodeList list = node.getChildNodes(); - for (int i=0; i 2.2") spec.add_development_dependency("concourse", "~> 0.41") - spec.add_development_dependency("hoe-markdown", "~> 1.1") + spec.add_development_dependency("hoe-markdown", "~> 1.4") spec.add_development_dependency("minitest", "~> 5.8") spec.add_development_dependency("minitest-reporters", "~> 1.4") spec.add_development_dependency("rake", "~> 13.0") diff --git a/rakelib/markdown.rake b/rakelib/markdown.rake index 068e8e30c9..4fd559d27a 100644 --- a/rakelib/markdown.rake +++ b/rakelib/markdown.rake @@ -1,2 +1,2 @@ require "hoe/markdown" -Hoe::Markdown::Standalone.new("nokogiri").define_markdown_tasks +Hoe::Markdown::Standalone.new("nokogiri").define_markdown_tasks("CHANGELOG.md") diff --git a/test/xml/test_node.rb b/test/xml/test_node.rb index cb7c0fd031..dd4ae4e858 100644 --- a/test/xml/test_node.rb +++ b/test/xml/test_node.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require "helper" require 'stringio' @@ -5,1228 +6,1237 @@ module Nokogiri module XML class TestNode < Nokogiri::TestCase - def setup - super - @xml = Nokogiri::XML(File.read(XML_FILE), XML_FILE) - end + describe Nokogiri::XML::Node do + let(:xml) { Nokogiri::XML(File.read(XML_FILE), XML_FILE) } - def test_first_element_child - node = @xml.root.first_element_child - assert_equal 'employee', node.name - assert node.element?, 'node is an element' - end + def test_first_element_child + node = xml.root.first_element_child + assert_equal('employee', node.name) + assert(node.element?, 'node is an element') + end - def test_element_children - nodes = @xml.root.element_children - assert_equal @xml.root.first_element_child, nodes.first - assert nodes.all?(&:element?), 'all nodes are elements' - end + def test_element_children + nodes = xml.root.element_children + assert_equal(xml.root.first_element_child, nodes.first) + assert(nodes.all?(&:element?), 'all nodes are elements') + end - def test_last_element_child - nodes = @xml.root.element_children - assert_equal nodes.last, @xml.root.element_children.last - end + def test_last_element_child + nodes = xml.root.element_children + assert_equal(nodes.last, xml.root.element_children.last) + end - def test_bad_xpath - bad_xpath = '//foo[' + def test_bad_xpath + bad_xpath = '//foo[' - begin - @xml.xpath(bad_xpath) - rescue Nokogiri::XML::XPath::SyntaxError => e - assert_match(bad_xpath, e.to_s) + begin + xml.xpath(bad_xpath) + rescue Nokogiri::XML::XPath::SyntaxError => e + assert_match(bad_xpath, e.to_s) + end end - end - def test_namespace_type_error - assert_raises(TypeError) do - @xml.root.namespace = Object.new + def test_namespace_type_error + assert_raises(TypeError) do + xml.root.namespace = Object.new + end end - end - def test_remove_namespace - @xml = Nokogiri::XML('') - tag = @xml.at('s') - assert tag.namespace - tag.namespace = nil - assert_nil tag.namespace - end - - def test_parse_needs_doc - list = @xml.root.parse('fooooooo ') - assert_equal 1, list.css('hello').length - end + def test_remove_namespace + xml = Nokogiri::XML('') + tag = xml.at('s') + assert(tag.namespace) + tag.namespace = nil + assert_nil(tag.namespace) + end - def test_parse - list = @xml.root.parse('fooooooo ') - assert_equal 2, list.length - end + def test_parse_needs_doc + list = xml.root.parse('fooooooo ') + assert_equal(1, list.css('hello').length) + end - def test_parse_with_block - called = false - list = @xml.root.parse('') { |cfg| - called = true - assert_instance_of Nokogiri::XML::ParseOptions, cfg - } - assert called, 'config block called' - assert_equal 1, list.length - end + def test_parse + list = xml.root.parse('fooooooo ') + assert_equal(2, list.length) + end - def test_parse_with_io - list = @xml.root.parse(StringIO.new('')) - assert_equal 1, list.length - assert_equal 'hello', list.first.name - end + def test_parse_with_block + called = false + list = xml.root.parse('') do |cfg| + called = true + assert_instance_of(Nokogiri::XML::ParseOptions, cfg) + end + assert(called, 'config block called') + assert_equal(1, list.length) + end - def test_parse_with_empty_string - list = @xml.root.parse('') - assert_equal 0, list.length - end + def test_parse_with_io + list = xml.root.parse(StringIO.new('')) + assert_equal(1, list.length) + assert_equal('hello', list.first.name) + end - def test_parse_config_option - node = @xml.root - options = nil - node.parse("") do |config| - options = config + def test_parse_with_empty_string + list = xml.root.parse('') + assert_equal(0, list.length) end - assert_equal Nokogiri::XML::ParseOptions::DEFAULT_XML, options.to_i - end - def test_node_context_parsing_of_malformed_html_fragment - doc = HTML.parse "
" - context_node = doc.at_css "div" - nodeset = context_node.parse("
") + def test_parse_config_option + node = xml.root + options = nil + node.parse("") do |config| + options = config + end + assert_equal(Nokogiri::XML::ParseOptions::DEFAULT_XML, options.to_i) + end - assert_equal 1, doc.errors.length - assert_equal 1, nodeset.length - assert_equal "
", nodeset.to_s - end + def test_node_context_parsing_of_malformed_html_fragment + doc = HTML.parse("
") + context_node = doc.at_css("div") + nodeset = context_node.parse("
") - def test_node_context_parsing_of_malformed_html_fragment_with_recover_is_corrected - doc = HTML.parse "
" - context_node = doc.at_css "div" - nodeset = context_node.parse("
") do |options| - options.recover + assert_equal(1, doc.errors.length) + assert_equal(1, nodeset.length) + assert_equal("
", nodeset.to_s) end - assert_equal 1, doc.errors.length - assert_equal 1, nodeset.length - assert_equal "
", nodeset.to_s - end + def test_node_context_parsing_of_malformed_html_fragment_with_recover_is_corrected + doc = HTML.parse("
") + context_node = doc.at_css("div") + nodeset = context_node.parse("
") do |options| + options.recover + end + + assert_equal(1, doc.errors.length) + assert_equal(1, nodeset.length) + assert_equal("
", nodeset.to_s) + end - def test_node_context_parsing_of_malformed_html_fragment_without_recover_is_not_corrected - doc = HTML.parse "
" - context_node = doc.at_css "div" - assert_raises(Nokogiri::XML::SyntaxError) do - context_node.parse("
") do |options| - options.strict + def test_node_context_parsing_of_malformed_html_fragment_without_recover_is_not_corrected + doc = HTML.parse("
") + context_node = doc.at_css("div") + assert_raises(Nokogiri::XML::SyntaxError) do + context_node.parse("
") do |options| + options.strict + end end end - end - def test_parse_error_list - error_count = @xml.errors.length - @xml.root.parse('') - assert(error_count < @xml.errors.length, "errors should have increased") - end + def test_parse_error_list + error_count = xml.errors.length + xml.root.parse('') + assert(error_count < xml.errors.length, "errors should have increased") + end - def test_parse_error_on_fragment_with_empty_document - doc = Document.new - fragment = DocumentFragment.new(doc, '') - node = fragment%'bar' - node.parse('<') - end + def test_parse_error_on_fragment_with_empty_document + doc = Document.new + fragment = DocumentFragment.new(doc, '') + node = fragment % 'bar' + node.parse('<') + end - def test_parse_with_unparented_text_context_node - doc = XML::Document.new - elem = XML::Text.new("foo", doc) - x = elem.parse("") # should not raise an exception - assert_equal x.first.name, "bar" - end + def test_parse_with_unparented_text_context_node + doc = XML::Document.new + elem = XML::Text.new("foo", doc) + x = elem.parse("") # should not raise an exception + assert_equal(x.first.name, "bar") + end - def test_parse_with_unparented_html_text_context_node - doc = HTML::Document.new - elem = XML::Text.new("div", doc) - x = elem.parse("
") # should not raise an exception - assert_equal x.first.name, "div" - end + def test_parse_with_unparented_html_text_context_node + doc = HTML::Document.new + elem = XML::Text.new("div", doc) + x = elem.parse("
") # should not raise an exception + assert_equal(x.first.name, "div") + end - def test_parse_with_unparented_fragment_text_context_node - doc = XML::DocumentFragment.parse "
foo
" - elem = doc.at_css "span" - x = elem.parse("") # should not raise an exception - assert_equal x.first.name, "span" - end + def test_parse_with_unparented_fragment_text_context_node + doc = XML::DocumentFragment.parse("
foo
") + elem = doc.at_css("span") + x = elem.parse("") # should not raise an exception + assert_equal(x.first.name, "span") + end - def test_parse_with_unparented_html_fragment_text_context_node - doc = HTML::DocumentFragment.parse "
foo
" - elem = doc.at_css "span" - x = elem.parse("") # should not raise an exception - assert_equal x.first.name, "span" - end + def test_parse_with_unparented_html_fragment_text_context_node + doc = HTML::DocumentFragment.parse("
foo
") + elem = doc.at_css("span") + x = elem.parse("") # should not raise an exception + assert_equal(x.first.name, "span") + end - def test_dup_is_deep_copy_by_default - doc = XML::Document.parse "

hello

" - div = doc.at_css "div" - node = div.dup - assert_equal 1, node.children.length - assert_equal "

hello

", node.children.first.to_html - end + def test_dup_is_deep_copy_by_default + doc = XML::Document.parse("

hello

") + div = doc.at_css("div") + node = div.dup + assert_equal(1, node.children.length) + assert_equal("

hello

", node.children.first.to_html) + end - def test_dup_deep_copy - doc = XML::Document.parse "

hello

" - div = doc.at_css "div" - node = div.dup(1) - assert_equal 1, node.children.length - assert_equal "

hello

", node.children.first.to_html - end + def test_dup_deep_copy + doc = XML::Document.parse("

hello

") + div = doc.at_css("div") + node = div.dup(1) + assert_equal(1, node.children.length) + assert_equal("

hello

", node.children.first.to_html) + end - def test_dup_shallow_copy - doc = XML::Document.parse "

hello

" - div = doc.at_css "div" - node = div.dup(0) - assert_equal 0, node.children.length - end + def test_dup_shallow_copy + doc = XML::Document.parse("

hello

") + div = doc.at_css("div") + node = div.dup(0) + assert_equal(0, node.children.length) + end - if Nokogiri.uses_libxml? def test_dup_to_another_document - doc1 = HTML::Document.parse "

hello

" - doc2 = HTML::Document.parse "
" + skip("Node.dup with new_parent arg is only implemented on CRuby") unless Nokogiri.uses_libxml? + doc1 = HTML::Document.parse("

hello

") + doc2 = HTML::Document.parse("
") - div = doc1.at_css "div" + div = doc1.at_css("div") duplicate_div = div.dup(1, doc2) - assert_not_nil doc1.at_css("div") - assert_equal doc2, duplicate_div.document - assert_equal 1, duplicate_div.children.length - assert_equal "

hello

", duplicate_div.children.first.to_html + assert_not_nil(doc1.at_css("div")) + assert_equal(doc2, duplicate_div.document) + assert_equal(1, duplicate_div.children.length) + assert_equal("

hello

", duplicate_div.children.first.to_html) end - end - def test_subclass_dup - subclass = Class.new(Nokogiri::XML::Node) - node = subclass.new('foo', @xml).dup - assert_instance_of subclass, node - end + def test_subclass_dup + subclass = Class.new(Nokogiri::XML::Node) + node = subclass.new('foo', xml).dup + assert_instance_of(subclass, node) + end - def test_gt_string_arg - node = @xml.at('employee') - nodes = (node > 'name') - assert_equal 1, nodes.length - assert_equal node, nodes.first.parent - end + def test_gt_string_arg + node = xml.at('employee') + nodes = (node > 'name') + assert_equal(1, nodes.length) + assert_equal(node, nodes.first.parent) + end - def test_next_element_when_next_sibling_is_element_should_return_next_sibling - doc = Nokogiri::XML "" - node = doc.at_css("foo") - next_element = node.next_element - assert next_element.element? - assert_equal doc.at_css("quux"), next_element - end + def test_next_element_when_next_sibling_is_element_should_return_next_sibling + doc = Nokogiri::XML("") + node = doc.at_css("foo") + next_element = node.next_element + assert(next_element.element?) + assert_equal(doc.at_css("quux"), next_element) + end - def test_next_element_when_there_is_no_next_sibling_should_return_nil - doc = Nokogiri::XML "" - assert_nil doc.at_css("quux").next_element - end + def test_next_element_when_there_is_no_next_sibling_should_return_nil + doc = Nokogiri::XML("") + assert_nil(doc.at_css("quux").next_element) + end - def test_next_element_when_next_sibling_is_not_an_element_should_return_closest_next_element_sibling - doc = Nokogiri::XML "bar" - node = doc.at_css("foo") - next_element = node.next_element - assert next_element.element? - assert_equal doc.at_css("quux"), next_element - end + def test_next_element_when_next_sibling_is_not_an_element_should_return_closest_next_element_sibling + doc = Nokogiri::XML("bar") + node = doc.at_css("foo") + next_element = node.next_element + assert(next_element.element?) + assert_equal(doc.at_css("quux"), next_element) + end - def test_next_element_when_next_sibling_is_not_an_element_and_no_following_element_should_return_nil - doc = Nokogiri::XML "bar" - node = doc.at_css("foo") - next_element = node.next_element - assert_nil next_element - end + def test_next_element_when_next_sibling_is_not_an_element_and_no_following_element_should_return_nil + doc = Nokogiri::XML("bar") + node = doc.at_css("foo") + next_element = node.next_element + assert_nil(next_element) + end - def test_previous_element_when_previous_sibling_is_element_should_return_previous_sibling - doc = Nokogiri::XML "" - node = doc.at_css("quux") - previous_element = node.previous_element - assert previous_element.element? - assert_equal doc.at_css("foo"), previous_element - end + def test_previous_element_when_previous_sibling_is_element_should_return_previous_sibling + doc = Nokogiri::XML("") + node = doc.at_css("quux") + previous_element = node.previous_element + assert(previous_element.element?) + assert_equal(doc.at_css("foo"), previous_element) + end - def test_previous_element_when_there_is_no_previous_sibling_should_return_nil - doc = Nokogiri::XML "" - assert_nil doc.at_css("foo").previous_element - end + def test_previous_element_when_there_is_no_previous_sibling_should_return_nil + doc = Nokogiri::XML("") + assert_nil(doc.at_css("foo").previous_element) + end - def test_previous_element_when_previous_sibling_is_not_an_element_should_return_closest_previous_element_sibling - doc = Nokogiri::XML "bar" - node = doc.at_css("quux") - previous_element = node.previous_element - assert previous_element.element? - assert_equal doc.at_css("foo"), previous_element - end + def test_previous_element_when_previous_sibling_is_not_an_element_should_return_closest_previous_element_sibling + doc = Nokogiri::XML("bar") + node = doc.at_css("quux") + previous_element = node.previous_element + assert(previous_element.element?) + assert_equal(doc.at_css("foo"), previous_element) + end - def test_previous_element_when_previous_sibling_is_not_an_element_and_no_following_element_should_return_nil - doc = Nokogiri::XML "foo" - node = doc.at_css("bar") - previous_element = node.previous_element - assert_nil previous_element - end + def test_previous_element_when_previous_sibling_is_not_an_element_and_no_following_element_should_return_nil + doc = Nokogiri::XML("foo") + node = doc.at_css("bar") + previous_element = node.previous_element + assert_nil(previous_element) + end - def test_element? - assert @xml.root.element?, 'is an element' - end + def test_element? + assert(xml.root.element?, 'is an element') + end - def test_slash_search - assert_equal 'EMP0001', (@xml/:staff/:employee/:employeeId).first.text - end + def test_slash_search + assert_equal('EMP0001', (xml / :staff / :employee / :employeeId).first.text) + end - def test_append_with_document - assert_raises(ArgumentError) do - @xml.root << Nokogiri::XML::Document.new + def test_append_with_document + assert_raises(ArgumentError) do + xml.root << Nokogiri::XML::Document.new + end end - end - def test_append_with_attr - r = Nokogiri.XML('').root - assert_raises(ArgumentError) do - r << r.at_xpath('@a') + def test_append_with_attr + r = Nokogiri.XML('').root + assert_raises(ArgumentError) do + r << r.at_xpath('@a') + end end - end - def test_inspect_ns - xml = Nokogiri::XML(<<-eoxml) { |c| c.noblanks } - - - - eoxml - ins = xml.inspect - - xml.traverse do |node| - assert_match node.class.name, ins - if node.respond_to? :attributes - node.attributes.each do |k,v| - assert_match k, ins - assert_match v, ins + def test_inspect_ns + xml = Nokogiri::XML(<<~eoxml) { |c| c.noblanks } + + + + eoxml + ins = xml.inspect + + xml.traverse do |node| + assert_match(node.class.name, ins) + if node.respond_to?(:attributes) + node.attributes.each do |k, v| + assert_match(k, ins) + assert_match(v, ins) + end end - end - if node.respond_to?(:namespace) && node.namespace - assert_match node.namespace.class.name, ins - assert_match node.namespace.href, ins + if node.respond_to?(:namespace) && node.namespace + assert_match(node.namespace.class.name, ins) + assert_match(node.namespace.href, ins) + end end end - end - def test_namespace_definitions_when_some_exist - xml = Nokogiri::XML <<-eoxml - - - - eoxml - namespace_definitions = xml.root.namespace_definitions - assert_equal 2, namespace_definitions.length - end - - def test_namespace_definitions_when_no_exist - xml = Nokogiri::XML <<-eoxml - - - - eoxml - namespace_definitions = xml.at_xpath('//xmlns:awesome').namespace_definitions - assert_equal 0, namespace_definitions.length - end + def test_namespace_definitions_when_some_exist + xml = Nokogiri::XML(<<~eoxml) + + + + eoxml + namespace_definitions = xml.root.namespace_definitions + assert_equal(2, namespace_definitions.length) + end - def test_namespace_goes_to_children - fruits = Nokogiri::XML(<<-eoxml) - - - eoxml - apple = Nokogiri::XML::Node.new('Apple', fruits) - orange = Nokogiri::XML::Node.new('Orange', fruits) - apple << orange - fruits.root << apple - assert fruits.at('//fruit:Orange',{'fruit'=>'www.fruits.org'}) - assert fruits.at('//fruit:Apple',{'fruit'=>'www.fruits.org'}) - end + def test_namespace_definitions_when_no_exist + xml = Nokogiri::XML(<<~eoxml) + + + + eoxml + namespace_definitions = xml.at_xpath('//xmlns:awesome').namespace_definitions + assert_equal(0, namespace_definitions.length) + end - def test_description - assert_nil @xml.at('employee').description - end + def test_namespace_goes_to_children + fruits = Nokogiri::XML(<<~eoxml) + + + eoxml + apple = Nokogiri::XML::Node.new('Apple', fruits) + orange = Nokogiri::XML::Node.new('Orange', fruits) + apple << orange + fruits.root << apple + assert(fruits.at('//fruit:Orange', { 'fruit' => 'www.fruits.org' })) + assert(fruits.at('//fruit:Apple', { 'fruit' => 'www.fruits.org' })) + end - def test_spaceship - nodes = @xml.xpath('//employee') - assert_equal(-1, (nodes.first <=> nodes.last)) - list = [nodes.first, nodes.last].sort - assert_equal nodes.first, list.first - assert_equal nodes.last, list.last - end + def test_description + assert_nil(xml.at('employee').description) + end - def test_incorrect_spaceship - nodes = @xml.xpath('//employee') - assert_nil(nodes.first <=> 'asdf') - end + def test_spaceship + nodes = xml.xpath('//employee') + assert_equal(-1, (nodes.first <=> nodes.last)) + list = [nodes.first, nodes.last].sort + assert_equal(nodes.first, list.first) + assert_equal(nodes.last, list.last) + end - def test_document_compare - nodes = @xml.xpath('//employee') - result = (nodes.first <=> @xml) + def test_incorrect_spaceship + nodes = xml.xpath('//employee') + assert_nil(nodes.first <=> 'asdf') + end - # Note that this behavior was changed in libxml@a005199 starting in v2.9.5. - # - # But that fix was backported by debian (and other distros?) into their v2.9.4 fork so we - # can't use version to detect what's going on here. Instead just shrug if we're using system - # libraries and the result is -1. - if (Nokogiri::VersionInfo.instance.libxml2_using_system?) - assert(result == 1 || result == -1) - else - assert_equal(1, result) + def test_document_compare + nodes = xml.xpath('//employee') + result = (nodes.first <=> xml) + + # Note that this behavior was changed in libxml@a005199 starting in v2.9.5. + # + # But that fix was backported by debian (and other distros?) into their v2.9.4 fork so we + # can't use version to detect what's going on here. Instead just shrug if we're using system + # libraries and the result is -1. + if Nokogiri::VersionInfo.instance.libxml2_using_system? + assert(result == 1 || result == -1) + else + assert_equal(1, result) + end end - end - def test_different_document_compare - nodes = @xml.xpath('//employee') - doc = Nokogiri::XML('') - b = doc.at('b') - assert_nil(nodes.first <=> b) - end + def test_different_document_compare + nodes = xml.xpath('//employee') + doc = Nokogiri::XML('') + b = doc.at('b') + assert_nil(nodes.first <=> b) + end - def test_duplicate_node_removes_namespace - fruits = Nokogiri::XML(<<-eoxml) - - - - eoxml - apple = fruits.root.xpath('fruit:Apple', {'fruit'=>'www.fruits.org'})[0] - new_apple = apple.dup - fruits.root << new_apple - assert_equal 2, fruits.xpath('//xmlns:Apple').length - assert_equal 1, fruits.to_xml.scan('www.fruits.org').length - end + def test_duplicate_node_removes_namespace + fruits = Nokogiri::XML(<<~eoxml) + + + + eoxml + apple = fruits.root.xpath('fruit:Apple', { 'fruit' => 'www.fruits.org' })[0] + new_apple = apple.dup + fruits.root << new_apple + assert_equal(2, fruits.xpath('//xmlns:Apple').length) + assert_equal(1, fruits.to_xml.scan('www.fruits.org').length) + end - [:clone, :dup].each do |symbol| - define_method "test_#{symbol}" do - node = @xml.at('//employee') - other = node.send(symbol) - assert_equal "employee", other.name - assert_nil other.parent + [:clone, :dup].each do |symbol| + define_method "test_#{symbol}" do + node = xml.at('//employee') + other = node.send(symbol) + assert_equal "employee", other.name + assert_nil other.parent + end end - end - def test_fragment_creates_elements - apple = @xml.fragment('') - apple.children.each do |child| - assert_equal Nokogiri::XML::Node::ELEMENT_NODE, child.type - assert_instance_of Nokogiri::XML::Element, child + def test_fragment_creates_elements + apple = xml.fragment('') + apple.children.each do |child| + assert_equal(Nokogiri::XML::Node::ELEMENT_NODE, child.type) + assert_instance_of(Nokogiri::XML::Element, child) + end end - end - def test_node_added_to_root_should_get_namespace - fruits = Nokogiri::XML(<<-eoxml) - - - eoxml - apple = fruits.fragment('') - fruits.root << apple - assert_equal 1, fruits.xpath('//xmlns:Apple').length - end + def test_node_added_to_root_should_get_namespace + fruits = Nokogiri::XML(<<~eoxml) + + + eoxml + apple = fruits.fragment('') + fruits.root << apple + assert_equal(1, fruits.xpath('//xmlns:Apple').length) + end - def test_new_node_can_have_ancestors - xml = Nokogiri::XML('text') - item = Nokogiri::XML::Element.new('item', xml) - assert_equal 0, item.ancestors.length - end + def test_new_node_can_have_ancestors + xml = Nokogiri::XML('text') + item = Nokogiri::XML::Element.new('item', xml) + assert_equal(0, item.ancestors.length) + end - def test_children - doc = Nokogiri::XML(<<-eoxml) - #{'' * 9 } - eoxml - assert_equal 9, doc.root.children.length - assert_equal 9, doc.root.children.to_a.length - - doc = Nokogiri::XML(<<-eoxml) - #{'' * 15 } - eoxml - assert_equal 15, doc.root.children.length - assert_equal 15, doc.root.children.to_a.length - end + def test_children + doc = Nokogiri::XML(<<~eoxml) + #{'' * 9} + eoxml + assert_equal(9, doc.root.children.length) + assert_equal(9, doc.root.children.to_a.length) + + doc = Nokogiri::XML(<<~eoxml) + #{'' * 15} + eoxml + assert_equal(15, doc.root.children.length) + assert_equal(15, doc.root.children.to_a.length) + end - def test_add_namespace - node = @xml.at('address') - node.add_namespace('foo', 'http://tenderlovemaking.com') - assert_equal 'http://tenderlovemaking.com', node.namespaces['xmlns:foo'] - end + def test_add_namespace + node = xml.at('address') + node.add_namespace('foo', 'http://tenderlovemaking.com') + assert_equal('http://tenderlovemaking.com', node.namespaces['xmlns:foo']) + end - def test_add_namespace_twice - node = @xml.at('address') - ns = node.add_namespace('foo', 'http://tenderlovemaking.com') - ns2 = node.add_namespace('foo', 'http://tenderlovemaking.com') - assert_equal ns, ns2 - end + def test_add_namespace_twice + node = xml.at('address') + ns = node.add_namespace('foo', 'http://tenderlovemaking.com') + ns2 = node.add_namespace('foo', 'http://tenderlovemaking.com') + assert_equal(ns, ns2) + end - def test_add_default_namespace - node = @xml.at('address') - node.add_namespace(nil, 'http://tenderlovemaking.com') - assert_equal 'http://tenderlovemaking.com', node.namespaces['xmlns'] - end + def test_add_default_namespace + node = xml.at('address') + node.add_namespace(nil, 'http://tenderlovemaking.com') + assert_equal('http://tenderlovemaking.com', node.namespaces['xmlns']) + end - def test_add_default_namespace_twice - node = @xml.at('address') - ns = node.add_namespace(nil, 'http://tenderlovemaking.com') - ns2 = node.add_namespace(nil, 'http://tenderlovemaking.com') - assert_equal ns.object_id, ns2.object_id - end + def test_add_default_namespace_twice + node = xml.at('address') + ns = node.add_namespace(nil, 'http://tenderlovemaking.com') + ns2 = node.add_namespace(nil, 'http://tenderlovemaking.com') + assert_equal(ns.object_id, ns2.object_id) + end - def test_add_multiple_namespaces - node = @xml.at('address') + def test_add_multiple_namespaces + node = xml.at('address') - node.add_namespace(nil, 'http://tenderlovemaking.com') - assert_equal 'http://tenderlovemaking.com', node.namespaces['xmlns'] + node.add_namespace(nil, 'http://tenderlovemaking.com') + assert_equal('http://tenderlovemaking.com', node.namespaces['xmlns']) - node.add_namespace('foo', 'http://tenderlovemaking.com') - assert_equal 'http://tenderlovemaking.com', node.namespaces['xmlns:foo'] - end + node.add_namespace('foo', 'http://tenderlovemaking.com') + assert_equal('http://tenderlovemaking.com', node.namespaces['xmlns:foo']) + end - def test_default_namespace= - node = @xml.at('address') - node.default_namespace = 'http://tenderlovemaking.com' - assert_equal 'http://tenderlovemaking.com', node.namespaces['xmlns'] - end + def test_default_namespace= + node = xml.at('address') + node.default_namespace = 'http://tenderlovemaking.com' + assert_equal('http://tenderlovemaking.com', node.namespaces['xmlns']) + end - def test_namespace= - node = @xml.at('address') - assert_nil node.namespace - definition = node.add_namespace_definition 'bar', 'http://tlm.com/' + def test_namespace= + node = xml.at('address') + assert_nil(node.namespace) + definition = node.add_namespace_definition('bar', 'http://tlm.com/') - node.namespace = definition + node.namespace = definition - assert_equal definition, node.namespace + assert_equal(definition, node.namespace) - assert_equal node, @xml.at('//foo:address', { - 'foo' => 'http://tlm.com/' - }) - end + assert_equal(node, xml.at('//foo:address', { + 'foo' => 'http://tlm.com/', + })) + end - def test_add_namespace_with_nil_associates_node - node = @xml.at('address') - assert_nil node.namespace - definition = node.add_namespace_definition nil, 'http://tlm.com/' - assert_equal definition, node.namespace - end + def test_add_namespace_with_nil_associates_node + node = xml.at('address') + assert_nil(node.namespace) + definition = node.add_namespace_definition(nil, 'http://tlm.com/') + assert_equal(definition, node.namespace) + end - def test_add_namespace_does_not_associate_node - node = @xml.at('address') - assert_nil node.namespace - assert node.add_namespace_definition 'foo', 'http://tlm.com/' - assert_nil node.namespace - end + def test_add_namespace_does_not_associate_node + node = xml.at('address') + assert_nil(node.namespace) + assert(node.add_namespace_definition('foo', 'http://tlm.com/')) + assert_nil(node.namespace) + end - def test_set_namespace_from_different_doc - node = @xml.at('address') - doc = Nokogiri::XML(File.read(XML_FILE), XML_FILE) - decl = doc.root.add_namespace_definition 'foo', 'bar' + def test_set_namespace_from_different_doc + node = xml.at('address') + doc = Nokogiri::XML(File.read(XML_FILE), XML_FILE) + decl = doc.root.add_namespace_definition('foo', 'bar') - assert_raises(ArgumentError) do - node.namespace = decl + assert_raises(ArgumentError) do + node.namespace = decl + end end - end - def test_set_namespace_must_only_take_a_namespace - node = @xml.at('address') - assert_raises(TypeError) do - node.namespace = node + def test_set_namespace_must_only_take_a_namespace + node = xml.at('address') + assert_raises(TypeError) do + node.namespace = node + end end - end - - def test_at - node = @xml.at('address') - assert_equal node, @xml.xpath('//address').first - end - def test_at_self - node = @xml.at('address') - assert_equal node, node.at('.') - end + def test_at + node = xml.at('address') + assert_equal(node, xml.xpath('//address').first) + end - def test_at_xpath - node = @xml.at_xpath('//address') - nodes = @xml.xpath('//address') - assert_equal 5, nodes.size - assert_equal node, nodes.first - end + def test_at_self + node = xml.at('address') + assert_equal(node, node.at('.')) + end - def test_at_css - node = @xml.at_css('address') - nodes = @xml.css('address') - assert_equal 5, nodes.size - assert_equal node, nodes.first - end + def test_at_xpath + node = xml.at_xpath('//address') + nodes = xml.xpath('//address') + assert_equal(5, nodes.size) + assert_equal(node, nodes.first) + end - def test_percent - node = @xml % ('address') - assert_equal node, @xml.xpath('//address').first - end + def test_at_css + node = xml.at_css('address') + nodes = xml.css('address') + assert_equal(5, nodes.size) + assert_equal(node, nodes.first) + end - def test_accept - visitor = Class.new { - attr_accessor :visited - def accept target - target.accept(self) - end + def test_percent + node = xml % 'address' + assert_equal(node, xml.xpath('//address').first) + end - def visit node - node.children.each { |c| c.accept(self) } - @visited = true - end - }.new - visitor.accept(@xml.root) - assert visitor.visited - end + def test_accept + visitor = Class.new do + attr_accessor :visited + def accept(target) + target.accept(self) + end - def test_write_to - io = StringIO.new - @xml.write_to io - io.rewind - assert_equal @xml.to_xml, io.read - end + def visit(node) + node.children.each { |c| c.accept(self) } + @visited = true + end + end.new + visitor.accept(xml.root) + assert(visitor.visited) + end - def test_write_to_with_block - called = false - io = StringIO.new - conf = nil - @xml.write_to io do |config| - called = true - conf = config - config.format.as_html.no_empty_tags - end - io.rewind - assert called - string = io.read - assert_equal @xml.serialize(nil, conf.options), string - assert_equal @xml.serialize(nil, conf), string - end + def test_write_to + io = StringIO.new + xml.write_to(io) + io.rewind + assert_equal(xml.to_xml, io.read) + end - %w{ xml html xhtml }.each do |type| - define_method(:"test_write_#{type}_to") do + def test_write_to_with_block + called = false io = StringIO.new - assert @xml.send(:"write_#{type}_to", io) + conf = nil + xml.write_to(io) do |config| + called = true + conf = config + config.format.as_html.no_empty_tags + end io.rewind - assert_match @xml.send(:"to_#{type}"), io.read + assert(called) + string = io.read + assert_equal(xml.serialize(nil, conf.options), string) + assert_equal(xml.serialize(nil, conf), string) end - end - def test_serialize_with_block - called = false - conf = nil - string = @xml.serialize do |config| - called = true - conf = config - config.format.as_html.no_empty_tags - end - assert called - assert_equal @xml.serialize(nil, conf.options), string - assert_equal @xml.serialize(nil, conf), string - end + %w{xml html xhtml}.each do |type| + define_method(:"test_write_#{type}_to") do + io = StringIO.new + assert xml.send(:"write_#{type}_to", io) + io.rewind + assert_match xml.send(:"to_#{type}"), io.read + end + end - def test_hold_refence_to_subnode - doc = Nokogiri::XML(<<-eoxml) - - - - - - eoxml - assert node_a = doc.css('a').first - assert node_b = node_a.css('b').first - node_a.unlink - assert_equal 'b', node_b.name - end + def test_serialize_with_block + called = false + conf = nil + string = xml.serialize do |config| + called = true + conf = config + config.format.as_html.no_empty_tags + end + assert(called) + assert_equal(xml.serialize(nil, conf.options), string) + assert_equal(xml.serialize(nil, conf), string) + end - def test_new - assert node = Nokogiri::XML::Node.new('input', @xml) - assert_equal 1, node.node_type - assert_instance_of Nokogiri::XML::Element, node - end + def test_hold_refence_to_subnode + doc = Nokogiri::XML(<<~eoxml) + + + + + + eoxml + assert(node_a = doc.css('a').first) + assert(node_b = node_a.css('b').first) + node_a.unlink + assert_equal('b', node_b.name) + end - def test_to_str - name = @xml.xpath('//name').first - assert_match(/Margaret/, '' + name) - assert_equal('Margaret Martin', '' + name.children.first) - end + def test_new + assert(node = Nokogiri::XML::Node.new('input', xml)) + assert_equal(1, node.node_type) + assert_instance_of(Nokogiri::XML::Element, node) + end - def test_ancestors - address = @xml.xpath('//address').first - assert_equal 3, address.ancestors.length - assert_equal ['employee', 'staff', 'document'], - address.ancestors.map(&:name) - end + def test_to_str + name = xml.xpath('//name').first + assert_match(/Margaret/, '' + name) + assert_equal('Margaret Martin', '' + name.children.first) + end - def test_read_only? - assert entity_decl = @xml.internal_subset.children.find { |x| - x.type == Node::ENTITY_DECL - } - assert entity_decl.read_only? - end + def test_ancestors + address = xml.xpath('//address').first + assert_equal(3, address.ancestors.length) + assert_equal(['employee', 'staff', 'document'], + address.ancestors.map(&:name)) + end - def test_set_content_with_symbol - node = @xml.at('//name') - node.content = :foo - assert_equal 'foo', node.content - end + def test_read_only? + assert(entity_decl = xml.internal_subset.children.find do |x| + x.type == Node::ENTITY_DECL + end) + assert(entity_decl.read_only?) + end - def test_set_native_content_is_unescaped - comment = Nokogiri.XML('').at('//comment()') + def test_set_content_with_symbol + node = xml.at('//name') + node.content = :foo + assert_equal('foo', node.content) + end - comment.native_content = " < " # content= will escape this string - assert_equal "", comment.to_xml - end + def test_set_native_content_is_unescaped + comment = Nokogiri.XML('').at('//comment()') - def test_find_by_css_class_with_nonstandard_whitespace - doc = Nokogiri::HTML "
" - assert_not_nil doc.at_css(".b") - end + comment.native_content = " < " # content= will escape this string + assert_equal("", comment.to_xml) + end - def test_find_by_css_with_tilde_eql - xml = Nokogiri::XML.parse(<<-eoxml) - - Hello world - Bar - Bar - Bar - Bar - Awesome - Awesome - - eoxml - set = xml.css('a[@class~="bar"]') - assert_equal 4, set.length - assert_equal ['Bar'], set.map(&:content).uniq - end + def test_find_by_css_class_with_nonstandard_whitespace + doc = Nokogiri::HTML("
") + assert_not_nil(doc.at_css(".b")) + end - def test_unlink - xml = Nokogiri::XML.parse(<<-eoxml) - - Bar - Bar - Bar - Hello world - Bar - Awesome - Awesome - - eoxml - node = xml.xpath('//a')[3] - assert_equal('Hello world', node.text) - assert_match(/Hello world/, xml.to_s) - assert node.parent - assert node.document - assert node.previous_sibling - assert node.next_sibling - node.unlink - assert !node.parent - #assert !node.document - assert !node.previous_sibling - assert !node.next_sibling - assert_no_match(/Hello world/, xml.to_s) - end + def test_find_by_css_with_tilde_eql + xml = Nokogiri::XML.parse(<<~eoxml) + + Hello world + Bar + Bar + Bar + Bar + Awesome + Awesome + + eoxml + set = xml.css('a[@class~="bar"]') + assert_equal(4, set.length) + assert_equal(['Bar'], set.map(&:content).uniq) + end - def test_next_sibling - assert node = @xml.root - assert sibling = node.child.next_sibling - assert_equal('employee', sibling.name) - end + def test_unlink + xml = Nokogiri::XML.parse(<<~eoxml) + + Bar + Bar + Bar + Hello world + Bar + Awesome + Awesome + + eoxml + node = xml.xpath('//a')[3] + assert_equal('Hello world', node.text) + assert_match(/Hello world/, xml.to_s) + assert(node.parent) + assert(node.document) + assert(node.previous_sibling) + assert(node.next_sibling) + node.unlink + assert(!node.parent) + # assert !node.document + assert(!node.previous_sibling) + assert(!node.next_sibling) + assert_no_match(/Hello world/, xml.to_s) + end - def test_previous_sibling - assert node = @xml.root - assert sibling = node.child.next_sibling - assert_equal('employee', sibling.name) - assert_equal(sibling.previous_sibling, node.child) - end + def test_next_sibling + assert(node = xml.root) + assert(sibling = node.child.next_sibling) + assert_equal('employee', sibling.name) + end - def test_name= - assert node = @xml.root - node.name = 'awesome' - assert_equal('awesome', node.name) - end + def test_previous_sibling + assert(node = xml.root) + assert(sibling = node.child.next_sibling) + assert_equal('employee', sibling.name) + assert_equal(sibling.previous_sibling, node.child) + end - def test_child - assert node = @xml.root - assert child = node.child - assert_equal('text', child.name) - end + def test_name= + assert(node = xml.root) + node.name = 'awesome' + assert_equal('awesome', node.name) + end - def test_key? - assert node = @xml.search('//address').first - assert(!node.key?('asdfasdf')) - end + def test_child + assert(node = xml.root) + assert(child = node.child) + assert_equal('text', child.name) + end - def test_set_property - assert node = @xml.search('//address').first - node['foo'] = 'bar' - assert_equal('bar', node['foo']) - end + def test_key? + assert(node = xml.search('//address').first) + assert(!node.key?('asdfasdf')) + end - def test_set_property_non_string - assert node = @xml.search('//address').first - node['foo'] = 1 - assert_equal('1', node['foo']) - node['foo'] = false - assert_equal('false', node['foo']) - end + def test_set_property + assert(node = xml.search('//address').first) + node['foo'] = 'bar' + assert_equal('bar', node['foo']) + end - def test_path - assert set = @xml.search('//employee') - assert node = set.first - assert_equal('/staff/employee[1]', node.path) - end + def test_set_property_non_string + assert(node = xml.search('//address').first) + node['foo'] = 1 + assert_equal('1', node['foo']) + node['foo'] = false + assert_equal('false', node['foo']) + end - def test_parent_xpath - assert set = @xml.search('//employee') - assert node = set.first - assert parent_set = node.search('..') - assert parent_node = parent_set.first - assert_equal '/staff', parent_node.path - assert_equal node.parent, parent_node - end + def test_path + assert(set = xml.search('//employee')) + assert(node = set.first) + assert_equal('/staff/employee[1]', node.path) + end - def test_search_self - node = @xml.at('//employee') - assert_equal node.search('.').to_a, [node] - end + def test_parent_xpath + assert(set = xml.search('//employee')) + assert(node = set.first) + assert(parent_set = node.search('..')) + assert(parent_node = parent_set.first) + assert_equal('/staff', parent_node.path) + assert_equal(node.parent, parent_node) + end - def test_search_by_symbol - assert set = @xml.search(:employee) - assert 5, set.length + def test_search_self + node = xml.at('//employee') + assert_equal(node.search('.').to_a, [node]) + end - assert node = @xml.at(:employee) - assert node.text =~ /EMP0001/ - end + def test_search_by_symbol + assert(set = xml.search(:employee)) + assert(5, set.length) - def test_new_node - node = Nokogiri::XML::Node.new('form', @xml) - assert_equal('form', node.name) - assert(node.document) - end + assert(node = xml.at(:employee)) + assert(node.text =~ /EMP0001/) + end - def test_encode_special_chars - foo = @xml.css('employee').first.encode_special_chars('&') - assert_equal '&', foo - end + def test_new_node + node = Nokogiri::XML::Node.new('form', xml) + assert_equal('form', node.name) + assert(node.document) + end - def test_content_equals - node = Nokogiri::XML::Node.new('form', @xml) - assert_equal('', node.content) + def test_encode_special_chars + foo = xml.css('employee').first.encode_special_chars('&') + assert_equal('&', foo) + end - node.content = 'hello world!' - assert_equal('hello world!', node.content) + def test_content_equals + node = Nokogiri::XML::Node.new('form', xml) + assert_equal('', node.content) - node.content = '& &' - assert_equal('& &', node.content) - assert_equal('
& <foo> &amp;
', node.to_xml) + node.content = 'hello world!' + assert_equal('hello world!', node.content) - node.content = "1234 <-> 1234" - assert_equal "1234 <-> 1234", node.content - assert_equal "
1234 <-> 1234
", node.to_xml + node.content = '& &' + assert_equal('& &', node.content) + assert_equal('
& <foo> &amp;
', node.to_xml) - node.content = '1234' - node.add_child '5678' - assert_equal '12345678', node.content - end + node.content = "1234 <-> 1234" + assert_equal("1234 <-> 1234", node.content) + assert_equal("
1234 <-> 1234
", node.to_xml) - # issue #839 - def test_encoding_of_copied_nodes - d1 = Nokogiri::XML('&') - d2 = Nokogiri::XML('') - ne = d1.root.xpath('//a').first.dup(1) - ne.content += "& < & > \" &" - d2.root << ne - assert_match(/&& < & > \" &<\/a>/, d2.to_s) - end + node.content = '1234' + node.add_child('5678') + assert_equal('12345678', node.content) + end - def test_content_after_appending_text - doc = Nokogiri::XML '' - node = doc.children.first - node.content = 'bar' - node << 'baz' - assert_equal 'barbaz', node.content - end + # issue #839 + def test_encoding_of_copied_nodes + d1 = Nokogiri::XML('&
') + d2 = Nokogiri::XML('') + ne = d1.root.xpath('//a').first.dup(1) + ne.content += "& < & > \" &" + d2.root << ne + assert_match(%r{&& < & > \" &}, d2.to_s) + end - def test_content_depth_first - node = Nokogiri::XML 'firstsecondthird' - assert_equal 'firstsecondthird', node.content - end + def test_content_after_appending_text + doc = Nokogiri::XML('') + node = doc.children.first + node.content = 'bar' + node << 'baz' + assert_equal('barbaz', node.content) + end - def test_set_content_should_unlink_existing_content - node = @xml.at_css("employee") - children = node.children - node.content = "hello" - children.each { |child| assert_nil child.parent } - end + def test_content_depth_first + node = Nokogiri::XML('firstsecondthird') + assert_equal('firstsecondthird', node.content) + end - def test_whitespace_nodes - doc = Nokogiri::XML.parse("Foo\nBar

Bazz

") - children = doc.at('//root').children.collect(&:to_s) - assert_equal "\n", children[1] - assert_equal " ", children[3] - end + def test_set_content_should_unlink_existing_content + node = xml.at_css("employee") + children = node.children + node.content = "hello" + children.each { |child| assert_nil(child.parent) } + end - def test_node_equality - doc1 = Nokogiri::XML.parse(File.read(XML_FILE), XML_FILE) - doc2 = Nokogiri::XML.parse(File.read(XML_FILE), XML_FILE) + def test_whitespace_nodes + doc = Nokogiri::XML.parse("Foo\nBar

Bazz

") + children = doc.at('//root').children.collect(&:to_s) + assert_equal("\n", children[1]) + assert_equal(" ", children[3]) + end - address1_1 = doc1.xpath('//address').first - address1_2 = doc1.xpath('//address').first + def test_node_equality + doc1 = Nokogiri::XML.parse(File.read(XML_FILE), XML_FILE) + doc2 = Nokogiri::XML.parse(File.read(XML_FILE), XML_FILE) - address2 = doc2.xpath('//address').first + address1_1 = doc1.xpath('//address').first + address1_2 = doc1.xpath('//address').first - assert_not_equal address1_1, address2 # two references to very, very similar nodes - assert_equal address1_1, address1_2 # two references to the exact same node - end + address2 = doc2.xpath('//address').first - def test_namespace_search_with_xpath_and_hash - xml = Nokogiri::XML.parse(<<-eoxml) - - - Michelin Model XGV - - - I'm a bicycle tire! - - - eoxml - - tires = xml.xpath('//bike:tire', {'bike' => 'http://schwinn.com/'}) - assert_equal 1, tires.length - end + assert_not_equal(address1_1, address2) # two references to very, very similar nodes + assert_equal(address1_1, address1_2) # two references to the exact same node + end - def test_namespace_search_with_xpath_and_hash_with_symbol_keys - xml = Nokogiri::XML.parse(<<-eoxml) - - - Michelin Model XGV - - - I'm a bicycle tire! - - - eoxml - - tires = xml.xpath('//bike:tire', :bike => 'http://schwinn.com/') - assert_equal 1, tires.length - end + def test_namespace_search_with_xpath_and_hash + xml = Nokogiri::XML.parse(<<~eoxml) + + + Michelin Model XGV + + + I'm a bicycle tire! + + + eoxml + + tires = xml.xpath('//bike:tire', { 'bike' => 'http://schwinn.com/' }) + assert_equal(1, tires.length) + end - def test_namespace_search_with_css - xml = Nokogiri::XML.parse(<<-eoxml) - - - Michelin Model XGV - - - I'm a bicycle tire! - - - eoxml - - tires = xml.css('bike|tire', 'bike' => 'http://schwinn.com/' ) - assert_equal 1, tires.length - end + def test_namespace_search_with_xpath_and_hash_with_symbol_keys + xml = Nokogiri::XML.parse(<<~eoxml) + + + Michelin Model XGV + + + I'm a bicycle tire! + + + eoxml + + tires = xml.xpath('//bike:tire', bike: 'http://schwinn.com/') + assert_equal(1, tires.length) + end - def test_namespaced_attribute_search_with_xpath - # from #593 - xmlContent = <<-EOXML - - - with namespace - no namespace - -EOXML - xml_doc = Nokogiri::XML(xmlContent) - - no_ns = xml_doc.xpath("//*[@att]") - assert_equal no_ns.length, 1 - assert_equal no_ns.first.content, "no namespace" - - with_ns = xml_doc.xpath("//*[@ns1:att]") - assert_equal with_ns.length, 1 - assert_equal with_ns.first.content, "with namespace" - end + def test_namespace_search_with_css + xml = Nokogiri::XML.parse(<<~eoxml) + + + Michelin Model XGV + + + I'm a bicycle tire! + + + eoxml + + tires = xml.css('bike|tire', 'bike' => 'http://schwinn.com/') + assert_equal(1, tires.length) + end - def test_namespaced_attribute_search_with_css - # from #593 - xmlContent = <<-EOXML - - - with namespace - no namespace - -EOXML - xml_doc = Nokogiri::XML(xmlContent) - - no_ns = xml_doc.css('*[att]') - assert_equal no_ns.length, 1 - assert_equal no_ns.first.content, "no namespace" - - with_ns = xml_doc.css('*[ns1|att]') - assert_equal with_ns.length, 1 - assert_equal with_ns.first.content, "with namespace" - end + def test_namespaced_attribute_search_with_xpath + # from #593 + xmlContent = <<~EOXML + + + with namespace + no namespace + + EOXML + xml_doc = Nokogiri::XML(xmlContent) + + no_ns = xml_doc.xpath("//*[@att]") + assert_equal(no_ns.length, 1) + assert_equal(no_ns.first.content, "no namespace") + + with_ns = xml_doc.xpath("//*[@ns1:att]") + assert_equal(with_ns.length, 1) + assert_equal(with_ns.first.content, "with namespace") + end - def test_namespaces_should_include_all_namespace_definitions - xml = Nokogiri::XML.parse(<<-EOF) - - - hello - - - - EOF - - namespaces = xml.namespaces # Document#namespace - assert_equal({"xmlns" => "http://quux.com/", - "xmlns:a" => "http://foo.com/", - "xmlns:b" => "http://bar.com/"}, namespaces) - - namespaces = xml.root.namespaces - assert_equal({"xmlns" => "http://quux.com/", - "xmlns:a" => "http://foo.com/", - "xmlns:b" => "http://bar.com/"}, namespaces) - - namespaces = xml.at_xpath("//xmlns:y").namespaces - assert_equal({"xmlns" => "http://quux.com/", - "xmlns:a" => "http://foo.com/", - "xmlns:b" => "http://bar.com/", - "xmlns:c" => "http://bazz.com/"}, namespaces) - - namespaces = xml.at_xpath("//xmlns:z").namespaces - assert_equal({"xmlns" => "http://quux.com/", - "xmlns:a" => "http://foo.com/", - "xmlns:b" => "http://bar.com/", - "xmlns:c" => "http://bazz.com/"}, namespaces) - - namespaces = xml.at_xpath("//xmlns:a").namespaces - assert_equal({"xmlns" => "http://quux.com/", - "xmlns:a" => "http://foo.com/", - "xmlns:b" => "http://bar.com/", - "xmlns:c" => "http://newc.com/"}, namespaces) - end + def test_namespaced_attribute_search_with_css + # from #593 + xmlContent = <<~EOXML + + + with namespace + no namespace + + EOXML + xml_doc = Nokogiri::XML(xmlContent) + + no_ns = xml_doc.css('*[att]') + assert_equal(no_ns.length, 1) + assert_equal(no_ns.first.content, "no namespace") + + with_ns = xml_doc.css('*[ns1|att]') + assert_equal(with_ns.length, 1) + assert_equal(with_ns.first.content, "with namespace") + end - def test_namespace - xml = Nokogiri::XML.parse(<<-EOF) - - - hello a - hello b - hello c -
-
hello moon
- - - EOF - set = xml.search("//y/*") - assert_equal "a", set[0].namespace.prefix - assert_equal 'http://foo.com/', set[0].namespace.href - assert_equal "b", set[1].namespace.prefix - assert_equal 'http://bar.com/', set[1].namespace.href - assert_equal "c", set[2].namespace.prefix - assert_equal 'http://bazz.com/', set[2].namespace.href - assert_nil set[3].namespace.prefix # default namespace - assert_equal 'http://ns.example.com/d', set[3].namespace.href - assert_nil set[4].namespace # no namespace - - assert_equal 'b', set[2].attributes['y'].namespace.prefix - assert_equal 'http://bar.com/', set[2].attributes['y'].namespace.href - assert_nil set[2].attributes['x'].namespace - assert_nil set[3].attributes['x'].namespace - assert_nil set[4].attributes['x'].namespace - end + def test_namespaces_should_include_all_namespace_definitions + xml = Nokogiri::XML.parse(<<~EOF) + + + hello +
+ + + EOF + + namespaces = xml.namespaces # Document#namespace + assert_equal({ "xmlns" => "http://quux.com/", + "xmlns:a" => "http://foo.com/", + "xmlns:b" => "http://bar.com/" }, namespaces) + + namespaces = xml.root.namespaces + assert_equal({ "xmlns" => "http://quux.com/", + "xmlns:a" => "http://foo.com/", + "xmlns:b" => "http://bar.com/" }, namespaces) + + namespaces = xml.at_xpath("//xmlns:y").namespaces + assert_equal({ "xmlns" => "http://quux.com/", + "xmlns:a" => "http://foo.com/", + "xmlns:b" => "http://bar.com/", + "xmlns:c" => "http://bazz.com/" }, namespaces) + + namespaces = xml.at_xpath("//xmlns:z").namespaces + assert_equal({ "xmlns" => "http://quux.com/", + "xmlns:a" => "http://foo.com/", + "xmlns:b" => "http://bar.com/", + "xmlns:c" => "http://bazz.com/" }, namespaces) + + namespaces = xml.at_xpath("//xmlns:a").namespaces + assert_equal({ "xmlns" => "http://quux.com/", + "xmlns:a" => "http://foo.com/", + "xmlns:b" => "http://bar.com/", + "xmlns:c" => "http://newc.com/" }, namespaces) + end + + def test_namespace + xml = Nokogiri::XML.parse(<<~EOF) + + + hello a + hello b + hello c +
+
hello moon
+ + + EOF + set = xml.search("//y/*") + assert_equal("a", set[0].namespace.prefix) + assert_equal('http://foo.com/', set[0].namespace.href) + assert_equal("b", set[1].namespace.prefix) + assert_equal('http://bar.com/', set[1].namespace.href) + assert_equal("c", set[2].namespace.prefix) + assert_equal('http://bazz.com/', set[2].namespace.href) + assert_nil(set[3].namespace.prefix) # default namespace + assert_equal('http://ns.example.com/d', set[3].namespace.href) + assert_nil(set[4].namespace) # no namespace + + assert_equal('b', set[2].attributes['y'].namespace.prefix) + assert_equal('http://bar.com/', set[2].attributes['y'].namespace.href) + assert_nil(set[2].attributes['x'].namespace) + assert_nil(set[3].attributes['x'].namespace) + assert_nil(set[4].attributes['x'].namespace) + end - if Nokogiri.uses_libxml? def test_namespace_without_an_href_on_html_node - # because microsoft word's HTML formatting does this. ick. - xml = Nokogiri::HTML.parse <<-EOF + # + # describe how we handle microsoft word's HTML formatting. + # this test is descriptive, not prescriptive. + # + skip("Xerces handles this edge case completely differently") unless Nokogiri.uses_libxml? + + xml = Nokogiri::HTML.parse(<<~EOF)
foo
EOF - assert_not_nil(node = xml.at('p')) + node = xml.at("p") + assert_not_nil(node) - assert_equal 1, node.namespaces.keys.size - assert node.namespaces.has_key?('xmlns:o') - assert_nil node.namespaces['xmlns:o'] + assert_equal(1, node.namespaces.keys.size) + assert(node.namespaces.has_key?('xmlns:o')) + assert_nil(node.namespaces['xmlns:o']) end - end - - def test_line - xml = Nokogiri::XML(<<-eoxml) - -
- Hello world - - - eoxml - - set = xml.search("//a") - node = set.first - assert_equal 2, node.line - end - def test_set_line - skip "Only supported with libxml2" unless Nokogiri.uses_libxml? - document = Nokogiri::XML::Document.new - node = document.create_element('a') - node.line = 54321 - assert_equal 54321, node.line - end + def test_xpath_results_have_document_and_are_decorated + x = Module.new do + def awesome!; end + end + util_decorate(xml, x) + node_set = xml.xpath("//employee") + assert_equal(xml, node_set.document) + assert(node_set.respond_to?(:awesome!)) + end - def test_xpath_results_have_document_and_are_decorated - x = Module.new do - def awesome! ; end + def test_css_results_have_document_and_are_decorated + x = Module.new do + def awesome!; end + end + util_decorate(xml, x) + node_set = xml.css("employee") + assert_equal(xml, node_set.document) + assert(node_set.respond_to?(:awesome!)) end - util_decorate(@xml, x) - node_set = @xml.xpath("//employee") - assert_equal @xml, node_set.document - assert node_set.respond_to?(:awesome!) - end - def test_css_results_have_document_and_are_decorated - x = Module.new do - def awesome! ; end + def test_blank + doc = Nokogiri::XML('') + assert_equal(false, doc.blank?) end - util_decorate(@xml, x) - node_set = @xml.css("employee") - assert_equal @xml, node_set.document - assert node_set.respond_to?(:awesome!) - end - def test_blank - doc = Nokogiri::XML('') - assert_equal false, doc.blank? - end + def test_to_xml_allows_to_serialize_with_as_xml_save_option + xml = Nokogiri::XML("
  • Hello world
") + set = xml.search("//ul") + node = set.first - def test_to_xml_allows_to_serialize_with_as_xml_save_option - xml = Nokogiri::XML("
  • Hello world
") - set = xml.search("//ul") - node = set.first + assert_no_match("
    \n
  • ", xml.to_xml(save_with: XML::Node::SaveOptions::AS_XML)) + assert_no_match("
      \n
    • ", node.to_xml(save_with: XML::Node::SaveOptions::AS_XML)) + end - assert_no_match("
        \n
      • ", xml.to_xml(:save_with => XML::Node::SaveOptions::AS_XML)) - assert_no_match("
          \n
        • ", node.to_xml(:save_with => XML::Node::SaveOptions::AS_XML)) - end + # issue 647 + def test_default_namespace_should_be_created + subject = Nokogiri::XML.parse('').root + ns = subject.attributes['bar'].namespace + assert_not_nil(ns) + assert_equal(ns.class, Nokogiri::XML::Namespace) + assert_equal('xml', ns.prefix) + assert_equal("http://www.w3.org/XML/1998/namespace", ns.href) + end - # issue 647 - def test_default_namespace_should_be_created - subject = Nokogiri::XML.parse('').root - ns = subject.attributes['bar'].namespace - assert_not_nil ns - assert_equal ns.class, Nokogiri::XML::Namespace - assert_equal 'xml', ns.prefix - assert_equal "http://www.w3.org/XML/1998/namespace", ns.href - end + # issue 648 + def test_namespace_without_prefix_should_be_set + node = Nokogiri::XML.parse('').root + subject = Nokogiri::XML::Node.new('foo', node.document) + subject.namespace = node.namespace + ns = subject.namespace + assert_equal(ns.class, Nokogiri::XML::Namespace) + assert_nil(ns.prefix) + assert_equal(ns.href, "http://bar.com") + end - # issue 648 - def test_namespace_without_prefix_should_be_set - node = Nokogiri::XML.parse('').root - subject = Nokogiri::XML::Node.new 'foo', node.document - subject.namespace = node.namespace - ns = subject.namespace - assert_equal ns.class, Nokogiri::XML::Namespace - assert_nil ns.prefix - assert_equal ns.href, "http://bar.com" - end + # issue 695 + def test_namespace_in_rendered_xml + document = Nokogiri::XML::Document.new + subject = Nokogiri::XML::Node.new('foo', document) + ns = subject.add_namespace(nil, 'bar') + subject.namespace = ns + assert_match(/xmlns="bar"/, subject.to_xml) + end - # issue 695 - def test_namespace_in_rendered_xml - document = Nokogiri::XML::Document.new - subject = Nokogiri::XML::Node.new 'foo', document - ns = subject.add_namespace nil, 'bar' - subject.namespace = ns - assert_match(/xmlns="bar"/, subject.to_xml) - end + # issue 771 + def test_format_noblank + content = <<~eoxml + + hello + + eoxml + subject = Nokogiri::XML(content) do |conf| + conf.default_xml.noblanks + end - # issue 771 - def test_format_noblank - content = < - hello - -eoxml - subject = Nokogiri::XML(content) do |conf| - conf.default_xml.noblanks + assert_match(%r{hello}, subject.to_xml(indent: 2)) end - assert_match %r{hello}, subject.to_xml(:indent => 2) - end + def test_text_node_colon + document = Nokogiri::XML::Document.new + root = Nokogiri::XML::Node.new('foo', document) + document.root = root + root << "hello:with_colon" + assert_match(/hello:with_colon/, document.to_xml) + end - def test_text_node_colon - document = Nokogiri::XML::Document.new - root = Nokogiri::XML::Node.new 'foo', document - document.root = root - root << "hello:with_colon" - assert_match(/hello:with_colon/, document.to_xml) - end + def test_document_eh + html_doc = Nokogiri::HTML("
          foo
          ") + xml_doc = Nokogiri::XML("
          foo
          ") + html_node = html_doc.at_css("div") + xml_node = xml_doc.at_css("div") - def test_document_eh - html_doc = Nokogiri::HTML "
          foo
          " - xml_doc = Nokogiri::XML "
          foo
          " - html_node = html_doc.at_css "div" - xml_node = xml_doc.at_css "div" + assert(html_doc.document?) + assert(xml_doc.document?) + assert(!html_node.document?) + assert(!xml_node.document?) + end - assert html_doc.document? - assert xml_doc.document? - assert ! html_node.document? - assert ! xml_node.document? - end + def test_processing_instruction_eh + xml_doc = Nokogiri::XML(%{\n\n\n
          foo
          }) + pi_node = xml_doc.children.first + div_node = xml_doc.at_css("div") + assert(pi_node.processing_instruction?) + assert(!div_node.processing_instruction?) + end - def test_processing_instruction_eh - xml_doc = Nokogiri::XML %Q{\n\n\n
          foo
          } - pi_node = xml_doc.children.first - div_node = xml_doc.at_css "div" - assert pi_node.processing_instruction? - assert ! div_node.processing_instruction? - end + def test_node_lang + document = Nokogiri::XML(<<~EOXML) + +
          +
          foo
          +
          +
          bar
          +
          bar
          +
          + EOXML + assert_equal("en", document.at_css(".english").lang) + assert_equal("en", document.at_css(".english_child").lang) + assert_equal("jp", document.at_css(".japanese").lang) + assert_nil(document.at_css(".unspecified").lang) + end - def test_node_lang - document = Nokogiri::XML <<-EOXML - -
          -
          foo
          -
          -
          bar
          -
          bar
          -
          - EOXML - assert_equal "en", document.at_css(".english").lang - assert_equal "en", document.at_css(".english_child").lang - assert_equal "jp", document.at_css(".japanese").lang - assert_nil document.at_css(".unspecified").lang - end + def test_set_node_lang + document = Nokogiri::XML("
          foo
          ") + subject = document.at_css(".subject") - def test_set_node_lang - document = Nokogiri::XML "
          foo
          " - subject = document.at_css(".subject") + subject.lang = "de" + assert_equal("de", subject.lang) - subject.lang = "de" - assert_equal "de", subject.lang + subject.lang = "fr" + assert_equal("fr", subject.lang) + end - subject.lang = "fr" - assert_equal "fr", subject.lang - end + def test_text_node_robustness_gh1426 + skip("No need to test libxml-ruby workarounds on JRuby") if Nokogiri.jruby? + # notably, the original bug report was about libxml-ruby interactions + # this test should blow up under valgrind if we regress on libxml-ruby workarounds + message = "

          BOOM!

          " + 10_000.times do + node = Nokogiri::HTML::DocumentFragment.parse(message).at_css("h2") + node.add_previous_sibling(Nokogiri::XML::Text.new('before', node.document)) + node.add_next_sibling(Nokogiri::XML::Text.new('after', node.document)) + end + end - def test_text_node_robustness_gh1426 - skip "No need to test libxml-ruby workarounds on JRuby" if Nokogiri.jruby? - # notably, the original bug report was about libxml-ruby interactions - # this test should blow up under valgrind if we regress on libxml-ruby workarounds - message = "

          BOOM!

          " - 10_000.times do - node = Nokogiri::HTML::DocumentFragment.parse(message).at_css("h2") - node.add_previous_sibling(Nokogiri::XML::Text.new('before', node.document)) - node.add_next_sibling(Nokogiri::XML::Text.new('after', node.document)) + def test_wrap + xml = '
          important thing
          ' + doc = Nokogiri::XML(xml) + thing = doc.at_css("thing") + thing.wrap("") + assert_equal('wrapper', thing.parent.name) + assert_equal('thing', doc.at_css("wrapper").children.first.name) + end + + describe "#line" do + it "returns a sensible line number for each node" do + xml = Nokogiri::XML(<<~eoxml) + + + Hello world + + + Goodbye world + + + eoxml + + set = xml.search("//b") + assert_equal(2, set[0].line) + assert_equal(5, set[1].line) + end end - end - def test_wrap - xml = '
          important thing
          ' - doc = Nokogiri::XML(xml) - thing = doc.at_css("thing") - thing.wrap("") - assert_equal 'wrapper', thing.parent.name - assert_equal 'thing', doc.at_css("wrapper").children.first.name + describe "#line=" do + it "overrides the line number of a node" do + skip("Xerces does not have line numbers for nodes") unless Nokogiri.uses_libxml? + document = Nokogiri::XML::Document.new + node = document.create_element('a') + node.line = 54321 + assert_equal(54321, node.line) + end + end end end end