require "helper" module Nokogiri module XML class TestNodeReparenting < Nokogiri::TestCase describe "standard node reparenting behavior" do # describe "namespace handling during reparenting" do # describe "given a Node" do # describe "with a Namespace" do # it "keeps the Namespace" # end # describe "given a parent Node with a default and a non-default Namespace" do # describe "passed an Node without a namespace" do # it "inserts an Node that inherits the default Namespace" # end # describe "passed a Node with a Namespace that matches the parent's non-default Namespace" do # it "inserts a Node that inherits the matching parent Namespace" # end # end # end # describe "given a markup string" do # describe "parsed relative to the document" do # describe "with a Namespace" do # it "keeps the Namespace" # end # describe "given a parent Node with a default and a non-default Namespace" do # describe "passed an Node without a namespace" do # it "inserts an Node that inherits the default Namespace" # end # describe "passed a Node with a Namespace that matches the parent's non-default Namespace" do # it "inserts a Node that inherits the matching parent Namespace" # end # end # end # describe "parsed relative to a specific node" do # describe "with a Namespace" do # it "keeps the Namespace" # end # describe "given a parent Node with a default and a non-default Namespace" do # describe "passed an Node without a namespace" do # it "inserts an Node that inherits the default Namespace" # end # describe "passed a Node with a Namespace that matches the parent's non-default Namespace" do # it "inserts a Node that inherits the matching parent Namespace" # end # end # end # end # end { :add_child => {:target => "/root/a1", :returns_self => false, :children_tags => %w[text b1 b2]}, :<< => {:target => "/root/a1", :returns_self => false, :children_tags => %w[text b1 b2]}, :replace => {:target => "/root/a1/node()", :returns_self => false, :children_tags => %w[b1 b2]}, :swap => {:target => "/root/a1/node()", :returns_self => true, :children_tags => %w[b1 b2]}, :children= => {:target => "/root/a1", :returns_self => false, :children_tags => %w[b1 b2]}, :inner_html= => {:target => "/root/a1", :returns_self => true, :children_tags => %w[b1 b2]}, :add_previous_sibling => {:target => "/root/a1/text()", :returns_self => false, :children_tags => %w[b1 b2 text]}, :previous= => {:target => "/root/a1/text()", :returns_self => false, :children_tags => %w[b1 b2 text]}, :before => {:target => "/root/a1/text()", :returns_self => true, :children_tags => %w[b1 b2 text]}, :add_next_sibling => {:target => "/root/a1/text()", :returns_self => false, :children_tags => %w[text b1 b2]}, :next= => {:target => "/root/a1/text()", :returns_self => false, :children_tags => %w[text b1 b2]}, :after => {:target => "/root/a1/text()", :returns_self => true, :children_tags => %w[text b1 b2]} }.each do |method, params| before do @doc = Nokogiri::XML "First nodeSecond nodeThird node" @doc2 = @doc.dup @fragment_string = "foobar" @fragment = Nokogiri::XML::DocumentFragment.parse @fragment_string @node_set = Nokogiri::XML("foobar").xpath("/root/node()") end describe "##{method}" do describe "passed a Node" do [:current, :another].each do |which| describe "passed a Node in the #{which} document" do before do @other_doc = which == :current ? @doc : @doc2 @other_node = @other_doc.at_xpath("/root/a2") end it "unlinks the Node from its previous position" do @doc.at_xpath(params[:target]).send(method, @other_node) @other_doc.at_xpath("/root/a2").must_be_nil end it "inserts the Node in the proper position" do @doc.at_xpath(params[:target]).send(method, @other_node) @doc.at_xpath("/root/a1/a2").wont_be_nil end it "returns the expected value" do sendee = @doc.at_xpath(params[:target]) result = sendee.send(method, @other_node) if params[:returns_self] result.must_equal sendee else result.must_equal @other_node end end end end end describe "passed a markup string" do it "inserts the fragment roots in the proper position" do @doc.at_xpath(params[:target]).send(method, @fragment_string) @doc.xpath("/root/a1/node()").collect {|n| n.name}.must_equal params[:children_tags] end it "returns the expected value" do sendee = @doc.at_xpath(params[:target]) result = sendee.send(method, @fragment_string) if params[:returns_self] result.must_equal sendee else result.must_be_kind_of Nokogiri::XML::NodeSet result.to_html.must_equal @fragment_string end end end describe "passed a fragment" do it "inserts the fragment roots in the proper position" do @doc.at_xpath(params[:target]).send(method, @fragment) @doc.xpath("/root/a1/node()").collect {|n| n.name}.must_equal params[:children_tags] end end describe "passed a document" do it "raises an exception" do proc { @doc.at_xpath("/root/a1").send(method, @doc2) }.must_raise(ArgumentError) end end describe "passed a non-Node" do it "raises an exception" do proc { @doc.at_xpath("/root/a1").send(method, 42) }.must_raise(ArgumentError) end end describe "passed a NodeSet" do it "inserts each member of the NodeSet in the proper order" do @doc.at_xpath(params[:target]).send(method, @node_set) @doc.xpath("/root/a1/node()").collect {|n| n.name}.must_equal params[:children_tags] end end end end describe "text node merging" do describe "#add_child" do it "merges the Text node with adjacent Text nodes" do @doc.at_xpath("/root/a1").add_child Nokogiri::XML::Text.new('hello', @doc) @doc.at_xpath("/root/a1/text()").content.must_equal "First nodehello" end end describe "#replace" do it "merges the Text node with adjacent Text nodes" do @doc.at_xpath("/root/a3/bx").replace Nokogiri::XML::Text.new('hello', @doc) @doc.at_xpath("/root/a3/text()").content.must_equal "Third hellonode" end end end end describe "ad hoc node reparenting behavior" do describe "#add_child" do describe "given a new node with a namespace" do it "keeps the namespace" do doc = Nokogiri::XML::Document.new item = Nokogiri::XML::Element.new('item', doc) doc.root = item entry = Nokogiri::XML::Element.new('entry', doc) entry.add_namespace('tlm', 'http://tenderlovemaking.com') assert_equal 'http://tenderlovemaking.com', entry.namespaces['xmlns:tlm'] item.add_child(entry) assert_equal 'http://tenderlovemaking.com', entry.namespaces['xmlns:tlm'] end end describe "given a parent node with a default namespace" do before do @doc = Nokogiri::XML(<<-eoxml) eoxml end it "inserts a node that inherits the default namespace" do assert node = @doc.at('//xmlns:first') child = Nokogiri::XML::Node.new('second', @doc) node.add_child(child) assert @doc.at('//xmlns:second') end end describe "given a parent node with a non-default namespace" do before do @doc = Nokogiri::XML(<<-eoxml) eoxml end describe "and a child node with a namespace matching the parent's non-default namespace" do it "inserts a node that inherits the matching parent namespace" do assert node = @doc.at('//xmlns:first') child = Nokogiri::XML::Node.new('second', @doc) ns = @doc.root.namespace_definitions.detect { |x| x.prefix == "foo" } child.namespace = ns node.add_child(child) assert @doc.at('//foo:second', "foo" => "http://flavorjon.es/") end end end end describe "#add_previous_sibling" do it "should not merge text nodes during the operation" do xml = Nokogiri::XML %Q(text node) replacee = xml.root.children.first replacee.add_previous_sibling "foo

bar" assert_equal "foo

bartext node", xml.root.children.to_html end end describe "#add_next_sibling" do it "should not merge text nodes during the operation" do xml = Nokogiri::XML %Q(text node) replacee = xml.root.children.first replacee.add_next_sibling "foo

bar" assert_equal "text nodefoo

bar", xml.root.children.to_html end end describe "#replace" do describe "a text node with a text node" do it "should not merge text nodes during the operation" do xml = Nokogiri::XML %Q(text node) replacee = xml.root.children.first replacee.replace "new text node" assert_equal "new text node", xml.root.children.first.content end end describe "when a document has a default namespace" do before do @fruits = Nokogiri::XML(<<-eoxml) eoxml end it "inserts a node with default namespaces" do apple = @fruits.css('apple').first orange = Nokogiri::XML::Node.new('orange', @fruits) apple.replace(orange) assert_equal orange, @fruits.css('orange').first end end end describe "unlinking a node and then reparenting it" do it "not blow up" do # see http://github.com/tenderlove/nokogiri/issues#issue/22 10.times do STDOUT.putc "." STDOUT.flush begin doc = Nokogiri::XML <<-EOHTML EOHTML assert root = doc.at("root") assert a = root.at("a") assert b = a.at("b") assert c = a.at("c") a.add_next_sibling(b.unlink) c.unlink end GC.start end end end describe "replace-merging text nodes" do [ ['a
', 'afoo'], ['a
b
', 'afoob'], ['
b
', 'foob'] ].each do |xml, result| it "doesn't blow up on #{xml}" do doc = Nokogiri::XML.parse(xml) saved_nodes = doc.root.children doc.at_xpath("/root/br").replace(Nokogiri::XML::Text.new('foo', doc)) saved_nodes.each { |child| child.inspect } # try to cause a crash assert_equal result, doc.at_xpath("/root/text()").inner_text end end end end end end end