require "helper"
module Nokogiri
module XML
class TestNodeSet < Nokogiri::TestCase
class TestNodeSetNamespaces < Nokogiri::TestCase
def setup
super
@xml = Nokogiri.XML('')
@list = @xml.xpath('//namespace::*')
end
def test_include?
assert @list.include?(@list.first), 'list should have item'
end
def test_push
@list.push @list.first
end
def test_delete
@list.push @list.first
@list.delete @list.first
end
def test_reference_after_delete
first = @list.first
@list.delete(first)
assert_equal 'http://www.w3.org/XML/1998/namespace', first.href
end
end
def setup
super
@xml = Nokogiri::XML(File.read(XML_FILE), XML_FILE)
@list = @xml.css('employee')
end
def test_break_works
assert_equal 7, @xml.root.elements.each { |x| break 7 }
end
def test_filter
list = @xml.css('address').filter('*[domestic="Yes"]')
assert_equal(%w{ Yes } * 4, list.map { |n| n['domestic'] })
end
def test_remove_attr
@list.each { |x| x['class'] = 'blah' }
assert_equal @list, @list.remove_attr('class')
@list.each { |x| assert_nil x['class'] }
end
def test_add_class
assert_equal @list, @list.add_class('bar')
@list.each { |x| assert_equal 'bar', x['class'] }
@list.add_class('bar')
@list.each { |x| assert_equal 'bar', x['class'] }
@list.add_class('baz')
@list.each { |x| assert_equal 'bar baz', x['class'] }
end
def test_remove_class_with_no_class
assert_equal @list, @list.remove_class('bar')
@list.each { |e| assert_nil e['class'] }
@list.each { |e| e['class'] = '' }
assert_equal @list, @list.remove_class('bar')
@list.each { |e| assert_nil e['class'] }
end
def test_remove_class_single
@list.each { |e| e['class'] = 'foo bar' }
assert_equal @list, @list.remove_class('bar')
@list.each { |e| assert_equal 'foo', e['class'] }
end
def test_remove_class_completely
@list.each { |e| e['class'] = 'foo' }
assert_equal @list, @list.remove_class
@list.each { |e| assert_nil e['class'] }
end
def test_attribute_set
@list.each { |e| assert_nil e['foo'] }
[ ['attribute', 'bar'], ['attr', 'biz'], ['set', 'baz'] ].each do |t|
@list.send(t.first.to_sym, 'foo', t.last)
@list.each { |e| assert_equal t.last, e['foo'] }
end
end
def test_attribute_set_with_block
@list.each { |e| assert_nil e['foo'] }
[ ['attribute', 'bar'], ['attr', 'biz'], ['set', 'baz'] ].each do |t|
@list.send(t.first.to_sym, 'foo') { |x| t.last }
@list.each { |e| assert_equal t.last, e['foo'] }
end
end
def test_attribute_set_with_hash
@list.each { |e| assert_nil e['foo'] }
[ ['attribute', 'bar'], ['attr', 'biz'], ['set', 'baz'] ].each do |t|
@list.send(t.first.to_sym, 'foo' => t.last)
@list.each { |e| assert_equal t.last, e['foo'] }
end
end
def test_attribute_no_args
@list.first['foo'] = 'bar'
assert_equal @list.first.attribute('foo'), @list.attribute('foo')
end
def test_search_empty_node_set
set = Nokogiri::XML::NodeSet.new(Nokogiri::XML::Document.new)
assert_equal 0, set.css('foo').length
assert_equal 0, set.xpath('.//foo').length
assert_equal 0, set.search('foo').length
end
def test_node_set_search_with_multiple_queries
xml = '
important thing
stuff
more stuff
'
set = Nokogiri::XML(xml).xpath(".//thing")
assert_kind_of Nokogiri::XML::NodeSet, set
assert_equal 3, set.xpath('./div', './p').length
assert_equal 3, set.css('.title', '.content', 'p').length
assert_equal 3, set.search('./div', 'p.blah').length
end
def test_search_with_custom_selector
set = @xml.xpath('//staff')
[
[:xpath, '//*[awesome(.)]'],
[:search, '//*[awesome(.)]'],
[:css, '*:awesome'],
[:search, '*:awesome']
].each do |method, query|
custom_employees = set.send(method, query, Class.new {
def awesome ns
ns.select { |n| n.name == 'employee' }
end
}.new)
assert_equal(@xml.xpath('//employee'), custom_employees,
"using #{method} with custom selector '#{query}'")
end
end
def test_search_with_variable_bindings
set = @xml.xpath('//staff')
assert_equal(4, set.xpath('//address[@domestic=$value]', nil, :value => 'Yes').length,
"using #xpath with variable binding")
assert_equal(4, set.search('//address[@domestic=$value]', nil, :value => 'Yes').length,
"using #search with variable binding")
end
def test_search_self
set = @xml.xpath('//staff')
assert_equal set.to_a, set.search('.').to_a
end
def test_css_searches_match_self
html = Nokogiri::HTML("
")
set = html.xpath("/html/body/div")
assert_equal set.first, set.css(".a").first
assert_equal set.first, set.search(".a").first
end
def test_css_search_with_namespace
fragment = Nokogiri::XML.fragment(<<-eoxml)
eoxml
assert fragment.children.search( 'body', { 'xmlns' => 'http://www.w3.org/1999/xhtml' })
end
def test_double_equal
assert node_set_one = @xml.xpath('//employee')
assert node_set_two = @xml.xpath('//employee')
assert_not_equal node_set_one.object_id, node_set_two.object_id
assert_equal node_set_one, node_set_two
end
def test_node_set_not_equal_to_string
node_set_one = @xml.xpath('//employee')
assert_not_equal node_set_one, "asdfadsf"
end
def test_out_of_order_not_equal
one = @xml.xpath('//employee')
two = @xml.xpath('//employee')
two.push two.shift
assert_not_equal one, two
end
def test_shorter_is_not_equal
node_set_one = @xml.xpath('//employee')
node_set_two = @xml.xpath('//employee')
node_set_two.delete(node_set_two.first)
assert_not_equal node_set_one, node_set_two
end
def test_pop
set = @xml.xpath('//employee')
last = set.last
assert_equal last, set.pop
end
def test_shift
set = @xml.xpath('//employee')
first = set.first
assert_equal first, set.shift
end
def test_shift_empty
set = Nokogiri::XML::NodeSet.new(@xml)
assert_nil set.shift
end
def test_pop_empty
set = Nokogiri::XML::NodeSet.new(@xml)
assert_nil set.pop
end
def test_first_takes_arguments
assert node_set = @xml.xpath('//employee')
assert_equal 2, node_set.first(2).length
end
def test_first_clamps_arguments
assert node_set = @xml.xpath('//employee[position() < 3]')
assert_equal 2, node_set.first(5).length
end
[:dup, :clone].each do |method_name|
define_method "test_#{method_name}" do
assert node_set = @xml.xpath('//employee')
duplicate = node_set.send(method_name)
assert_equal node_set.length, duplicate.length
node_set.zip(duplicate).each do |a,b|
assert_equal a, b
end
end
end
def test_dup_on_empty_set
empty_set = Nokogiri::XML::NodeSet.new @xml, []
assert_equal 0, empty_set.dup.length # this shouldn't raise null pointer exception
end
def test_xmlns_is_automatically_registered
doc = Nokogiri::XML(<<-eoxml)
eoxml
set = doc.css('foo')
assert_equal 1, set.css('xmlns|bar').length
assert_equal 0, set.css('|bar').length
assert_equal 1, set.xpath('//xmlns:bar').length
assert_equal 1, set.search('xmlns|bar').length
assert_equal 1, set.search('//xmlns:bar').length
assert set.at('//xmlns:bar')
assert set.at('xmlns|bar')
assert set.at('bar')
end
def test_children_has_document
set = @xml.root.children
assert_instance_of(NodeSet, set)
assert_equal @xml, set.document
end
def test_length_size
assert node_set = @xml.search('//employee')
assert_equal node_set.length, node_set.size
end
def test_to_xml
assert node_set = @xml.search('//employee')
assert node_set.to_xml
end
def test_inner_html
doc = Nokogiri::HTML(<<-eohtml)
eohtml
assert html = doc.css('div').inner_html
assert_match '', html
end
def test_gt_string_arg
assert node_set = @xml.search('//employee')
assert_equal node_set.xpath('./employeeId'), (node_set > 'employeeId')
end
def test_at_performs_a_search_with_css
assert node_set = @xml.search('//employee')
assert_equal node_set.first.first_element_child, node_set.at('employeeId')
assert_equal node_set.first.first_element_child, node_set.%('employeeId')
end
def test_at_performs_a_search_with_xpath
assert node_set = @xml.search('//employee')
assert_equal node_set.first.first_element_child, node_set.at('./employeeId')
assert_equal node_set.first.first_element_child, node_set.%('./employeeId')
end
def test_at_with_integer_index
assert node_set = @xml.search('//employee')
assert_equal node_set.first, node_set.at(0)
assert_equal node_set.first, node_set % 0
end
def test_at_xpath
assert node_set = @xml.search('//employee')
assert_equal node_set.first.first_element_child, node_set.at_xpath('./employeeId')
end
def test_at_css
assert node_set = @xml.search('//employee')
assert_equal node_set.first.first_element_child, node_set.at_css('employeeId')
end
def test_to_ary
assert node_set = @xml.search('//employee')
foo = []
foo += node_set
assert_equal node_set.length, foo.length
end
def test_push
node = Nokogiri::XML::Node.new('foo', @xml)
node.content = 'bar'
assert node_set = @xml.search('//employee')
node_set.push(node)
assert node_set.include?(node)
end
def test_delete_with_invalid_argument
employees = @xml.search("//employee")
positions = @xml.search("//position")
assert_raises(ArgumentError) { employees.delete(positions) }
end
def test_delete_when_present
employees = @xml.search("//employee")
wally = employees.first
assert employees.include?(wally) # testing setup
length = employees.length
result = employees.delete(wally)
assert_equal result, wally
assert ! employees.include?(wally)
assert length-1, employees.length
end
def test_delete_when_not_present
employees = @xml.search("//employee")
phb = @xml.search("//position").first
assert ! employees.include?(phb) # testing setup
length = employees.length
result = employees.delete(phb)
assert_nil result
assert length, employees.length
end
def test_delete_on_empty_set
empty_set = Nokogiri::XML::NodeSet.new @xml, []
employee = @xml.at_xpath("//employee")
assert_equal nil, empty_set.delete(employee)
end
def test_unlink
xml = Nokogiri::XML.parse(<<-eoxml)
Bar
Bar
Bar
Hello world
Bar
Awesome
Awesome
eoxml
set = xml.xpath('//a')
set.unlink
set.each do |node|
assert !node.parent
#assert !node.document
assert !node.previous_sibling
assert !node.next_sibling
end
assert_no_match(/Hello world/, xml.to_s)
end
def test_nodeset_search_takes_namespace
@xml = Nokogiri::XML.parse(<<-eoxml)
Michelin Model XGV
I'm a bicycle tire!
eoxml
set = @xml/'root'
assert_equal 1, set.length
bike_tire = set.search('//bike:tire', 'bike' => "http://schwinn.com/")
assert_equal 1, bike_tire.length
end
def test_new_nodeset
node_set = Nokogiri::XML::NodeSet.new(@xml)
assert_equal(0, node_set.length)
node = Nokogiri::XML::Node.new('form', @xml)
node_set << node
assert_equal(1, node_set.length)
assert_equal(node, node_set.last)
end
def test_search_on_nodeset
assert node_set = @xml.search('//employee')
assert sub_set = node_set.search('.//name')
assert_equal(node_set.length, sub_set.length)
end
def test_negative_index_works
assert node_set = @xml.search('//employee')
assert_equal node_set.last, node_set[-1]
end
def test_large_negative_index_returns_nil
assert node_set = @xml.search('//employee')
assert_nil(node_set[-1 * (node_set.length + 1)])
end
def test_node_set_fetches_private_data
assert node_set = @xml.search('//employee')
set = node_set
assert_equal(set[0], set[0])
end
def test_node_set_returns_0
assert node_set = @xml.search('//asdkfjhasdlkfjhaldskfh')
assert_equal(0, node_set.length)
end
def test_wrap
employees = (@xml/"//employee").wrap("")
assert_equal 'wrapper', employees[0].parent.name
assert_equal 'employee', @xml.search("//wrapper").first.children[0].name
end
def test_wrap_a_fragment
frag = Nokogiri::XML::DocumentFragment.parse <<-EOXML
hello
goodbye
EOXML
employees = frag.xpath ".//employee"
employees.wrap("")
assert_equal 'wrapper', employees[0].parent.name
assert_equal 'employee', frag.at(".//wrapper").children.first.name
end
def test_wrap_preserves_document_structure
assert_equal "employeeId",
@xml.at_xpath("//employee").children.detect{|j| ! j.text? }.name
@xml.xpath("//employeeId[text()='EMP0001']").wrap("")
assert_equal "wrapper",
@xml.at_xpath("//employee").children.detect{|j| ! j.text? }.name
end
def test_plus_operator
names = @xml.search("name")
positions = @xml.search("position")
names_len = names.length
positions_len = positions.length
assert_raises(ArgumentError) { names + positions.first }
result = names + positions
assert_equal names_len, names.length
assert_equal positions_len, positions.length
assert_equal names.length + positions.length, result.length
names += positions
assert_equal result.length, names.length
end
def test_union
names = @xml.search("name")
assert_equal(names.length, (names | @xml.search("name")).length)
end
def test_minus_operator
employees = @xml.search("//employee")
females = @xml.search("//employee[gender[text()='Female']]")
employees_len = employees.length
females_len = females.length
assert_raises(ArgumentError) { employees - females.first }
result = employees - females
assert_equal employees_len, employees.length
assert_equal females_len, females.length
assert_equal employees.length - females.length, result.length
employees -= females
assert_equal result.length, employees.length
end
def test_array_index
employees = @xml.search("//employee")
other = @xml.search("//position").first
assert_equal 3, employees.index(employees[3])
assert_nil employees.index(other)
end
def test_slice_too_far
employees = @xml.search("//employee")
assert_equal employees.length, employees[0, employees.length + 1].length
assert_equal employees.length, employees[0, employees.length].length
end
def test_slice_on_empty_node_set
empty_set = Nokogiri::XML::NodeSet.new @xml, []
assert_equal nil, empty_set[99]
assert_equal nil, empty_set[99..101]
assert_equal nil, empty_set[99,2]
end
def test_slice_waaaaaay_off_the_end
xml = Nokogiri::XML::Builder.new {
root { 100.times { div } }
}.doc
nodes = xml.css "div"
assert_equal 1, nodes.slice(99, 100_000).length
assert_equal 0, nodes.slice(100, 100_000).length
end
def test_array_slice_with_start_and_end
employees = @xml.search("//employee")
assert_equal [employees[1], employees[2], employees[3]], employees[1,3].to_a
end
def test_array_index_bracket_equivalence
employees = @xml.search("//employee")
assert_equal [employees[1], employees[2], employees[3]], employees[1,3].to_a
assert_equal [employees[1], employees[2], employees[3]], employees.slice(1,3).to_a
end
def test_array_slice_with_negative_start
employees = @xml.search("//employee")
assert_equal [employees[2]], employees[-3,1].to_a
assert_equal [employees[2], employees[3]], employees[-3,2].to_a
end
def test_array_slice_with_invalid_args
employees = @xml.search("//employee")
assert_nil employees[99, 1] # large start
assert_nil employees[1, -1] # negative len
assert_equal [], employees[1, 0].to_a # zero len
end
def test_array_slice_with_range
employees = @xml.search("//employee")
assert_equal [employees[1], employees[2], employees[3]], employees[1..3].to_a
assert_equal [employees[0], employees[1], employees[2], employees[3]], employees[0..3].to_a
end
def test_intersection_with_no_overlap
employees = @xml.search("//employee")
positions = @xml.search("//position")
assert_equal [], (employees & positions).to_a
end
def test_intersection
employees = @xml.search("//employee")
first_set = employees[0..2]
second_set = employees[2..4]
assert_equal [employees[2]], (first_set & second_set).to_a
end
def test_intersection_on_empty_set
empty_set = Nokogiri::XML::NodeSet.new @xml
employees = @xml.search("//employee")
assert_equal 0, (empty_set & employees).length
end
def test_include?
employees = @xml.search("//employee")
yes = employees.first
no = @xml.search("//position").first
assert employees.include?(yes)
assert ! employees.include?(no)
end
def test_include_on_empty_node_set
empty_set = Nokogiri::XML::NodeSet.new @xml, []
employee = @xml.at_xpath("//employee")
assert ! empty_set.include?(employee)
end
def test_children
employees = @xml.search("//employee")
count = 0
employees.each do |employee|
count += employee.children.length
end
set = employees.children
assert_equal count, set.length
end
def test_inspect
employees = @xml.search("//employee")
inspected = employees.inspect
assert_equal "[#{employees.map(&:inspect).join(', ')}]",
inspected
end
def test_should_not_splode_when_accessing_namespace_declarations_in_a_node_set
2.times do
xml = Nokogiri::XML ""
node_set = xml.xpath("//namespace::*")
assert_equal 1, node_set.size
node = node_set.first
node.to_s # segfaults in 1.4.0 and earlier
# if we haven't segfaulted, let's make sure we handled it correctly
assert_instance_of Nokogiri::XML::Namespace, node
end
end
def test_should_not_splode_when_arrayifying_node_set_containing_namespace_declarations
xml = Nokogiri::XML ""
node_set = xml.xpath("//namespace::*")
assert_equal 1, node_set.size
node_array = node_set.to_a
node = node_array.first
node.to_s # segfaults in 1.4.0 and earlier
# if we haven't segfaulted, let's make sure we handled it correctly
assert_instance_of Nokogiri::XML::Namespace, node
end
def test_should_not_splode_when_unlinking_node_set_containing_namespace_declarations
xml = Nokogiri::XML ""
node_set = xml.xpath("//namespace::*")
assert_equal 1, node_set.size
node_set.unlink
end
def test_reverse
xml = Nokogiri::XML "bd"
children = xml.root.children
assert_instance_of Nokogiri::XML::NodeSet, children
reversed = children.reverse
assert_equal reversed[0], children[4]
assert_equal reversed[1], children[3]
assert_equal reversed[2], children[2]
assert_equal reversed[3], children[1]
assert_equal reversed[4], children[0]
assert_equal children, children.reverse.reverse
end
def test_node_set_dup_result_has_document_and_is_decorated
x = Module.new do
def awesome! ; end
end
util_decorate(@xml, x)
node_set = @xml.css("address")
new_set = node_set.dup
assert_equal node_set.document, new_set.document
assert new_set.respond_to?(:awesome!)
end
def test_node_set_union_result_has_document_and_is_decorated
x = Module.new do
def awesome! ; end
end
util_decorate(@xml, x)
node_set1 = @xml.css("address")
node_set2 = @xml.css("address")
new_set = node_set1 | node_set2
assert_equal node_set1.document, new_set.document
assert new_set.respond_to?(:awesome!)
end
def test_node_set_intersection_result_has_document_and_is_decorated
x = Module.new do
def awesome! ; end
end
util_decorate(@xml, x)
node_set1 = @xml.css("address")
node_set2 = @xml.css("address")
new_set = node_set1 & node_set2
assert_equal node_set1.document, new_set.document
assert new_set.respond_to?(:awesome!)
end
def test_node_set_difference_result_has_document_and_is_decorated
x = Module.new do
def awesome! ; end
end
util_decorate(@xml, x)
node_set1 = @xml.css("address")
node_set2 = @xml.css("address")
new_set = node_set1 - node_set2
assert_equal node_set1.document, new_set.document
assert new_set.respond_to?(:awesome!)
end
def test_node_set_slice_result_has_document_and_is_decorated
x = Module.new do
def awesome! ; end
end
util_decorate(@xml, x)
node_set = @xml.css("address")
new_set = node_set[0..-1]
assert_equal node_set.document, new_set.document
assert new_set.respond_to?(:awesome!)
end
end
end
end