require 'xml'
require 'test/unit'
require 'stringio'
class TestParser < Test::Unit::TestCase
def setup
XML::Error.set_handler(&XML::Error::QUIET_HANDLER)
end
def teardown
GC.start
GC.start
GC.start
end
# ----- Sources ------
def test_document
file = File.expand_path(File.join(File.dirname(__FILE__), 'model/bands.xml'))
parser = XML::Parser.file(file)
doc = parser.parse
parser = XML::Parser.document(doc)
doc = parser.parse
assert_instance_of(XML::Document, doc)
assert_instance_of(XML::Parser::Context, parser.context)
end
def test_nil_document
error = assert_raise(TypeError) do
XML::Parser.document(nil)
end
assert_equal("Must pass an XML::Document object", error.to_s)
end
def test_file
file = File.expand_path(File.join(File.dirname(__FILE__), 'model/rubynet.xml'))
parser = XML::Parser.file(file)
doc = parser.parse
assert_instance_of(XML::Document, doc)
assert_instance_of(XML::Parser::Context, parser.context)
end
def test_noexistent_file
error = assert_raise(XML::Error) do
XML::Parser.file('i_dont_exist.xml')
end
assert_equal('Warning: failed to load external entity "i_dont_exist.xml".', error.to_s)
end
def test_nil_file
error = assert_raise(TypeError) do
XML::Parser.file(nil)
end
assert_equal("can't convert nil into String", error.to_s)
end
def test_file_encoding
file = File.expand_path(File.join(File.dirname(__FILE__), 'model/bands.xml'))
parser = XML::Parser.file(file, :encoding => XML::Encoding::ISO_8859_1)
error = assert_raise(XML::Error) do
doc = parser.parse
end
assert(error.to_s.match(/Fatal error: Extra content at the end of the document/))
parser = XML::Parser.file(file, :encoding => XML::Encoding::UTF_8)
doc = parser.parse
assert_not_nil(doc)
end
def test_file_base_uri
file = File.expand_path(File.join(File.dirname(__FILE__), 'model/bands.xml'))
parser = XML::Parser.file(file)
doc = parser.parse
assert(doc.child.base.match(/test\/model\/bands.xml/))
parser = XML::Parser.file(file, :base_uri => "http://libxml.org")
doc = parser.parse
assert(doc.child.base.match(/test\/model\/bands.xml/))
end
def test_io
File.open(File.join(File.dirname(__FILE__), 'model/rubynet.xml')) do |io|
parser = XML::Parser.io(io)
assert_instance_of(XML::Parser, parser)
doc = parser.parse
assert_instance_of(XML::Document, doc)
assert_instance_of(XML::Parser::Context, parser.context)
end
end
def test_io_gc
# Test that the reader keeps a reference
# to the io object
file = File.open(File.join(File.dirname(__FILE__), 'model/rubynet.xml'))
parser = XML::Parser.io(file)
file = nil
GC.start
assert(parser.parse)
end
def test_nil_io
error = assert_raise(TypeError) do
XML::Parser.io(nil)
end
assert_equal("Must pass in an IO object", error.to_s)
end
def test_string_io
data = File.read(File.join(File.dirname(__FILE__), 'model/rubynet.xml'))
string_io = StringIO.new(data)
parser = XML::Parser.io(string_io)
doc = parser.parse
assert_instance_of(XML::Document, doc)
assert_instance_of(XML::Parser::Context, parser.context)
end
def test_string
str = 'onetwo'
parser = XML::Parser.string(str)
assert_instance_of(XML::Parser, parser)
doc = parser.parse
assert_instance_of(XML::Document, doc)
assert_instance_of(XML::Parser::Context, parser.context)
end
def test_nil_string
error = assert_raise(TypeError) do
XML::Parser.string(nil)
end
assert_equal("wrong argument type nil (expected String)", error.to_s)
end
def test_string_options
xml = <<-EOS
]>
&foo;
EOS
XML::default_substitute_entities = false
# Parse normally
parser = XML::Parser.string(xml)
doc = parser.parse
assert_nil(doc.child.base)
# Cdata section should be cdata nodes
node = doc.find_first('/test/cdata').child
assert_equal(XML::Node::CDATA_SECTION_NODE, node.node_type)
# Entities should not be subtituted
node = doc.find_first('/test/entity')
assert_equal('&foo;', node.child.to_s)
# Parse with options
parser = XML::Parser.string(xml, :base_uri => 'http://libxml.rubyforge.org',
:options => XML::Parser::Options::NOCDATA | XML::Parser::Options::NOENT)
doc = parser.parse
assert_equal(doc.child.base_uri, 'http://libxml.rubyforge.org')
# Cdata section should be text nodes
node = doc.find_first('/test/cdata').child
assert_equal(XML::Node::TEXT_NODE, node.node_type)
# Entities should be subtituted
node = doc.find_first('/test/entity')
assert_equal('bar', node.child.to_s)
end
def test_string_encoding
# ISO_8859_1:
# ö - f6 in hex, \366 in octal
# ü - fc in hex, \374 in octal
xml = <<-EOS
m\366tley_cr\374e
EOS
# Parse as UTF_8
parser = XML::Parser.string(xml)
error = assert_raise(XML::Error) do
doc = parser.parse
end
assert_equal("Fatal error: Input is not proper UTF-8, indicate encoding !\nBytes: 0xF6 0x74 0x6C 0x65 at :2.",
error.to_s)
# Parse as ISO_8859_1:
parser = XML::Parser.string(xml, :encoding => XML::Encoding::ISO_8859_1)
doc = parser.parse
node = doc.find_first('//metal')
assert_equal("m\303\266tley_cr\303\274e", node.content)
end
def test_fd_gc
# Test opening # of documents up to the file limit for the OS.
# Ideally it should run until libxml emits a warning,
# thereby knowing we've done a GC sweep. For the time being,
# re-open the same doc `limit descriptors` times.
# If we make it to the end, then we've succeeded,
# otherwise an exception will be thrown.
XML::Error.set_handler {|error|}
max_fd = if RUBY_PLATFORM.match(/mswin32/i)
500
else
(`ulimit -n`.chomp.to_i) + 1
end
file = File.join(File.dirname(__FILE__), 'model/rubynet.xml')
max_fd.times do
XML::Parser.file(file).parse
end
XML::Error.reset_handler {|error|}
end
# ----- Errors ------
def test_error
error = assert_raise(XML::Error) do
XML::Parser.string('').parse
end
assert_not_nil(error)
assert_kind_of(XML::Error, error)
assert_equal("Fatal error: Opening and ending tag mismatch: foo line 1 and foz at :1.", error.message)
assert_equal(XML::Error::PARSER, error.domain)
assert_equal(XML::Error::TAG_NAME_MISMATCH, error.code)
assert_equal(XML::Error::FATAL, error.level)
assert_nil(error.file)
assert_equal(1, error.line)
assert_equal('foo', error.str1)
assert_equal('foz', error.str2)
assert_nil(error.str3)
assert_equal(1, error.int1)
assert_equal(20, error.int2)
assert_nil(error.node)
end
def test_bad_xml
parser = XML::Parser.string('onetwo')
error = assert_raise(XML::Error) do
assert_not_nil(parser.parse)
end
assert_not_nil(error)
assert_kind_of(XML::Error, error)
assert_equal("Fatal error: Extra content at the end of the document at :1.", error.message)
assert_equal(XML::Error::PARSER, error.domain)
assert_equal(XML::Error::DOCUMENT_END, error.code)
assert_equal(XML::Error::FATAL, error.level)
assert_nil(error.file)
assert_equal(1, error.line)
assert_nil(error.str1)
assert_nil(error.str2)
assert_nil(error.str3)
assert_equal(0, error.int1)
assert_equal(20, error.int2)
assert_nil(error.node)
end
# Deprecated methods
def test_document_deprecated
file = File.expand_path(File.join(File.dirname(__FILE__), 'model/bands.xml'))
parser = XML::Parser.file(file)
doc = parser.parse
parser = XML::Parser.new
parser.document = doc
doc = parser.parse
assert_instance_of(XML::Document, doc)
assert_instance_of(XML::Parser::Context, parser.context)
end
def test_file_deprecated
file = File.expand_path(File.join(File.dirname(__FILE__), 'model/rubynet.xml'))
parser = XML::Parser.new
parser.file = file
doc = parser.parse
assert_instance_of(XML::Document, doc)
assert_instance_of(XML::Parser::Context, parser.context)
end
def test_io_deprecated
File.open(File.join(File.dirname(__FILE__), 'model/rubynet.xml')) do |io|
parser = XML::Parser.new
assert_instance_of(XML::Parser, parser)
parser.io = io
doc = parser.parse
assert_instance_of(XML::Document, doc)
assert_instance_of(XML::Parser::Context, parser.context)
end
end
def test_string_deprecated
str = 'onetwo'
parser = XML::Parser.new
parser.string = str
assert_instance_of(XML::Parser, parser)
doc = parser.parse
assert_instance_of(XML::Document, doc)
assert_instance_of(XML::Parser::Context, parser.context)
end
end