Skip to content

Commit

Permalink
Added CDATA support to the XmlMini LibXML engine, adjusted whitespace…
Browse files Browse the repository at this point in the history
… handling to closer match that of the REXML engine, and added a LibXML engine test

Signed-off-by: Michael Koziarski <michael@koziarski.com>
  • Loading branch information
jlauemoeller authored and NZKoz committed Oct 14, 2009
1 parent 3fa7e2f commit fc46c9b
Show file tree
Hide file tree
Showing 2 changed files with 202 additions and 5 deletions.
13 changes: 8 additions & 5 deletions activesupport/lib/active_support/xml_mini/libxml.rb
Expand Up @@ -13,8 +13,6 @@ def parse(data)
data = StringIO.new(data || '')
end

LibXML::XML.default_keep_blanks = false

char = data.getc
if char.nil?
{}
Expand Down Expand Up @@ -44,9 +42,9 @@ module Node #:nodoc:
# hash::
# Hash to merge the converted element into.
def to_hash(hash={})
if text?
raise LibXML::XML::Error if content.length >= LIB_XML_LIMIT
hash[CONTENT_ROOT] = content
if text? || cdata?
raise LibXML::XML::Error if hash[CONTENT_ROOT].to_s.length + content.length >= LIB_XML_LIMIT
hash[CONTENT_ROOT] = hash[CONTENT_ROOT].to_s + content
else
sub_hash = insert_name_into_hash(hash, name)
attributes_to_hash(sub_hash)
Expand Down Expand Up @@ -88,6 +86,11 @@ def insert_name_into_hash(hash, name)
# Hash to merge the children into.
def children_to_hash(hash={})
each { |child| child.to_hash(hash) }

if hash.length > 1 && hash[CONTENT_ROOT].blank?
hash.delete(CONTENT_ROOT)
end

attributes_to_hash(hash)
hash
end
Expand Down
194 changes: 194 additions & 0 deletions activesupport/test/xml_mini/libxml_engine_test.rb
@@ -0,0 +1,194 @@
require 'abstract_unit'
require 'active_support/xml_mini'
require 'active_support/core_ext/hash/conversions'

begin
require 'libxml'
rescue LoadError
# Skip libxml tests
else

class LibxmlEngineTest < Test::Unit::TestCase
include ActiveSupport

def setup
@default_backend = XmlMini.backend
XmlMini.backend = 'LibXML'

LibXML::XML::Error.set_handler(&lambda { |error| }) #silence libxml, exceptions will do
end

def teardown
XmlMini.backend = @default_backend
end

def test_exception_thrown_on_expansion_attack
assert_raise LibXML::XML::Error do
attack_xml = %{<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE member [
<!ENTITY a "&b;&b;&b;&b;&b;&b;&b;&b;&b;&b;">
<!ENTITY b "&c;&c;&c;&c;&c;&c;&c;&c;&c;&c;">
<!ENTITY c "&d;&d;&d;&d;&d;&d;&d;&d;&d;&d;">
<!ENTITY d "&e;&e;&e;&e;&e;&e;&e;&e;&e;&e;">
<!ENTITY e "&f;&f;&f;&f;&f;&f;&f;&f;&f;&f;">
<!ENTITY f "&g;&g;&g;&g;&g;&g;&g;&g;&g;&g;">
<!ENTITY g "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx">
]>
<member>
&a;
</member>
}
Hash.from_xml(attack_xml)
end
end

def test_setting_libxml_as_backend
XmlMini.backend = 'LibXML'
assert_equal XmlMini_LibXML, XmlMini.backend
end

def test_blank_returns_empty_hash
assert_equal({}, XmlMini.parse(nil))
assert_equal({}, XmlMini.parse(''))
end

def test_array_type_makes_an_array
assert_equal_rexml(<<-eoxml)
<blog>
<posts type="array">
<post>a post</post>
<post>another post</post>
</posts>
</blog>
eoxml
end

def test_one_node_document_as_hash
assert_equal_rexml(<<-eoxml)
<products/>
eoxml
end

def test_one_node_with_attributes_document_as_hash
assert_equal_rexml(<<-eoxml)
<products foo="bar"/>
eoxml
end

def test_products_node_with_book_node_as_hash
assert_equal_rexml(<<-eoxml)
<products>
<book name="awesome" id="12345" />
</products>
eoxml
end

def test_products_node_with_two_book_nodes_as_hash
assert_equal_rexml(<<-eoxml)
<products>
<book name="awesome" id="12345" />
<book name="america" id="67890" />
</products>
eoxml
end

def test_single_node_with_content_as_hash
assert_equal_rexml(<<-eoxml)
<products>
hello world
</products>
eoxml
end

def test_children_with_children
assert_equal_rexml(<<-eoxml)
<root>
<products>
<book name="america" id="67890" />
</products>
</root>
eoxml
end

def test_children_with_text
assert_equal_rexml(<<-eoxml)
<root>
<products>
hello everyone
</products>
</root>
eoxml
end

def test_children_with_non_adjacent_text
assert_equal_rexml(<<-eoxml)
<root>
good
<products>
hello everyone
</products>
morning
</root>
eoxml
end

def test_parse_from_io
io = StringIO.new(<<-eoxml)
<root>
good
<products>
hello everyone
</products>
morning
</root>
eoxml
XmlMini.parse(io)
end

def test_children_with_simple_cdata
assert_equal_rexml(<<-eoxml)
<root>
<products>
<![CDATA[cdatablock]]>
</products>
</root>
eoxml
end

def test_children_with_multiple_cdata
assert_equal_rexml(<<-eoxml)
<root>
<products>
<![CDATA[cdatablock1]]><![CDATA[cdatablock2]]>
</products>
</root>
eoxml
end

def test_children_with_text_and_cdata
assert_equal_rexml(<<-eoxml)
<root>
<products>
hello <![CDATA[cdatablock]]>
morning
</products>
</root>
eoxml
end

def test_children_with_blank_text
assert_equal_rexml(<<-eoxml)
<root>
<products> </products>
</root>
eoxml
end

private
def assert_equal_rexml(xml)
hash = XmlMini.with_backend('REXML') { XmlMini.parse(xml) }
assert_equal(hash, XmlMini.parse(xml))
end
end

end

0 comments on commit fc46c9b

Please sign in to comment.