mezza-testunitxml 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/test/unit/xml.rb +21 -0
- data/lib/test/unit/xml/attributes_mixin.rb +21 -0
- data/lib/test/unit/xml/conditionals.rb +141 -0
- data/lib/test/unit/xml/doctype_mixin.rb +54 -0
- data/lib/test/unit/xml/nodeiterator.rb +61 -0
- data/lib/test/unit/xml/notationdecl_mixin.rb +54 -0
- data/lib/test/unit/xml/xml_assertions.rb +163 -0
- data/lib/test/unit/xml/xmlequalfilter.rb +31 -0
- metadata +66 -0
@@ -0,0 +1,21 @@
|
|
1
|
+
=begin rdoc
|
2
|
+
This file mixes in XML assertions in the Test::Unit::TestCase
|
3
|
+
class.
|
4
|
+
|
5
|
+
See #xml_assertions.rb for information about the assertions
|
6
|
+
that are mixed in.
|
7
|
+
=end
|
8
|
+
|
9
|
+
require 'test/unit/xml/xml_assertions'
|
10
|
+
|
11
|
+
module Test
|
12
|
+
module Unit
|
13
|
+
|
14
|
+
# The module Test::Unit::XML is mixed in into the class
|
15
|
+
# Test::Unit::TestCase
|
16
|
+
class TestCase
|
17
|
+
include Test::Unit::XML
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module REXML
|
2
|
+
|
3
|
+
# The REXML::Attributes mix-in adds methods that are useful for
|
4
|
+
# attribute collections, but not present in the standard
|
5
|
+
# REXML::Attributes class
|
6
|
+
class Attributes
|
7
|
+
|
8
|
+
# The +get_attribute_ns+ method retrieves a method by its namespace
|
9
|
+
# and name. Thus it is possible to reliably identify an attribute
|
10
|
+
# even if an XML processor has changed the prefix.
|
11
|
+
def get_attribute_ns(namespace, name)
|
12
|
+
each_attribute() { |attribute|
|
13
|
+
if name == attribute.name &&
|
14
|
+
namespace == attribute.namespace()
|
15
|
+
return attribute
|
16
|
+
end
|
17
|
+
}
|
18
|
+
nil
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
|
2
|
+
module Test
|
3
|
+
module Unit
|
4
|
+
module XML
|
5
|
+
|
6
|
+
# This singleton class compares all types of REXML nodes.
|
7
|
+
class Conditionals
|
8
|
+
|
9
|
+
private_class_method :new
|
10
|
+
@@conditionals = nil
|
11
|
+
|
12
|
+
# The +create+ method is used to create a singleton instance
|
13
|
+
# of the Conditionals class.
|
14
|
+
def Conditionals.create
|
15
|
+
@@conditionals = new unless @@conditionals
|
16
|
+
@@conditionals
|
17
|
+
end
|
18
|
+
|
19
|
+
# The method compares two REXML nodes representing an XML document,
|
20
|
+
# or part of a document. If the nodes are equal, the method returns
|
21
|
+
# +true+. If the nodes are not equal, the method returns +false+.
|
22
|
+
# If the nodes have child nodes, for example if the nodes are
|
23
|
+
# +Element+ nodes with content, they will _not_ be recursively compared.
|
24
|
+
def compare_xml_nodes(expected_node, actual_node)
|
25
|
+
return false unless actual_node.instance_of? expected_node.class
|
26
|
+
case actual_node
|
27
|
+
when REXML::Document
|
28
|
+
# TODO: Implement Document comparison
|
29
|
+
true
|
30
|
+
when REXML::DocType
|
31
|
+
compare_doctypes(expected_node, actual_node)
|
32
|
+
when REXML::Element :
|
33
|
+
compare_elements(expected_node, actual_node)
|
34
|
+
when REXML::CData
|
35
|
+
compare_texts(expected_node, actual_node)
|
36
|
+
when REXML::Text
|
37
|
+
compare_texts(expected_node, actual_node)
|
38
|
+
when REXML::Comment
|
39
|
+
compare_comments(expected_node, actual_node)
|
40
|
+
when REXML::Instruction
|
41
|
+
compare_pi(expected_node, actual_node)
|
42
|
+
when REXML::XMLDecl
|
43
|
+
compare_xml_declaration(expected_node, actual_node)
|
44
|
+
#when REXML::Entity
|
45
|
+
# compare_xml_entities(expected_node, actual_node)
|
46
|
+
else
|
47
|
+
puts "Unknown node type #{actual_node.class}"
|
48
|
+
false
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def compare_doctypes(expected_node, actual_node)
|
55
|
+
return compare_system_id(expected_node.system, actual_node.system) &&
|
56
|
+
expected_node.public == actual_node.public &&
|
57
|
+
compare_xml_internal_dtd_subset(expected_node, actual_node)
|
58
|
+
end
|
59
|
+
|
60
|
+
def compare_system_id(expected_id, actual_id)
|
61
|
+
is_expected_urn = expected_id =~ /^urn:/i
|
62
|
+
is_actual_urn = actual_id =~ /^urn:/i
|
63
|
+
if is_expected_urn || is_actual_urn
|
64
|
+
expected_id == actual_id
|
65
|
+
else
|
66
|
+
true
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def compare_elements(expected_node, actual_node)
|
71
|
+
return expected_node.name == actual_node.name &&
|
72
|
+
expected_node.namespace() == actual_node.namespace() &&
|
73
|
+
compare_attributes(expected_node.attributes, actual_node.attributes)
|
74
|
+
end
|
75
|
+
|
76
|
+
def compare_attributes(expected_attributes, actual_attributes)
|
77
|
+
return false unless attribute_count(expected_attributes) == attribute_count(actual_attributes)
|
78
|
+
expected_attributes.each_attribute do |expected_attribute|
|
79
|
+
expected_prefix = expected_attribute.prefix()
|
80
|
+
unless expected_prefix == 'xmlns' then
|
81
|
+
expected_name = expected_attribute.name
|
82
|
+
expected_namespace = expected_attribute.namespace
|
83
|
+
actual_attribute = actual_attributes.get_attribute_ns(expected_namespace, expected_name)
|
84
|
+
return false unless actual_attribute
|
85
|
+
return false if expected_attribute.value() != actual_attribute.value()
|
86
|
+
end
|
87
|
+
end
|
88
|
+
true
|
89
|
+
end
|
90
|
+
|
91
|
+
def attribute_count(attributes)
|
92
|
+
# Do not count namespace declarations
|
93
|
+
attributes.size - attributes.prefixes.size
|
94
|
+
end
|
95
|
+
|
96
|
+
def compare_texts(expected_node, actual_node)
|
97
|
+
expected_node.value.eql?(actual_node.value)
|
98
|
+
end
|
99
|
+
|
100
|
+
def compare_comments(expected_node, actual_node)
|
101
|
+
expected_node == actual_node
|
102
|
+
end
|
103
|
+
|
104
|
+
def compare_pi(expected_pi, actual_pi)
|
105
|
+
return expected_pi.target == actual_pi.target &&
|
106
|
+
expected_pi.content == actual_pi.content
|
107
|
+
end
|
108
|
+
|
109
|
+
def compare_xml_declaration(expected_decl, actual_decl)
|
110
|
+
return expected_decl == actual_decl
|
111
|
+
end
|
112
|
+
|
113
|
+
def compare_xml_internal_dtd_subset(expected_node, actual_node)
|
114
|
+
expected_subset = expected_node.children()
|
115
|
+
actual_subset = actual_node.children()
|
116
|
+
return false unless expected_subset.length == actual_subset.length
|
117
|
+
expected_subset.inject(true) { |memo, expected_decl|
|
118
|
+
case expected_decl
|
119
|
+
when REXML::Entity
|
120
|
+
memo &&
|
121
|
+
expected_decl.value == actual_node.entities[expected_decl.name].value &&
|
122
|
+
expected_decl.ndata == actual_node.entities[expected_decl.name].ndata
|
123
|
+
when REXML::NotationDecl
|
124
|
+
actual_notation_decl = actual_node.notation(expected_decl.name)
|
125
|
+
memo &&
|
126
|
+
actual_notation_decl != nil &&
|
127
|
+
expected_decl.name == actual_notation_decl.name &&
|
128
|
+
expected_decl.public == actual_notation_decl.public &&
|
129
|
+
expected_decl.system == actual_notation_decl.system
|
130
|
+
when REXML::Comment
|
131
|
+
true
|
132
|
+
else
|
133
|
+
raise "Unexpected node type in internal DTD subset of expected document: " + expected_decl.inspect
|
134
|
+
end
|
135
|
+
}
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
|
2
|
+
require 'test/unit/xml/notationdecl_mixin'
|
3
|
+
|
4
|
+
module REXML
|
5
|
+
|
6
|
+
# The REXML::DocType mix-in adds methods that are useful for
|
7
|
+
# Doctype declarations, but not present in the standard
|
8
|
+
# REXML::DocType class
|
9
|
+
class DocType
|
10
|
+
|
11
|
+
# This method retrieves the public identifier identifying the document's DTD.
|
12
|
+
def public
|
13
|
+
case @external_id
|
14
|
+
when "SYSTEM"
|
15
|
+
nil
|
16
|
+
when "PUBLIC"
|
17
|
+
strip_quotes(@long_name)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# This method retrieves the system identifier identifying the document's DTD
|
22
|
+
def system
|
23
|
+
case @external_id
|
24
|
+
when "SYSTEM"
|
25
|
+
strip_quotes(@long_name)
|
26
|
+
when "PUBLIC"
|
27
|
+
@uri.kind_of?(String) ? strip_quotes(@uri) : nil
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# This method returns a list of notations that have been declared in the
|
32
|
+
# _internal_ DTD subset. Notations in the external DTD subset are not listed.
|
33
|
+
def notations
|
34
|
+
children().select {|node| node.kind_of?(REXML::NotationDecl)}
|
35
|
+
end
|
36
|
+
|
37
|
+
# Retrieves a named notation. Only notations declared in the internal
|
38
|
+
# DTD subset can be retrieved.
|
39
|
+
def notation(name)
|
40
|
+
notations.find { |notation_decl|
|
41
|
+
notation_decl.name == name
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def strip_quotes(quoted_string)
|
48
|
+
quoted_string =~ /^[\'\"].*[\�\"]$/ ?
|
49
|
+
quoted_string[1, quoted_string.length-2] :
|
50
|
+
quoted_string
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
#! /usr/bin/ruby
|
2
|
+
|
3
|
+
module Test
|
4
|
+
module Unit
|
5
|
+
module XML
|
6
|
+
class NodeIterator
|
7
|
+
|
8
|
+
class NullNodeFilter
|
9
|
+
def accept(node)
|
10
|
+
true
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# This class method takes a node as an argument and locates the
|
15
|
+
# next node. The first argument is a node. The second argument
|
16
|
+
# is an optional node filter.
|
17
|
+
def NodeIterator.find_next_node(node, node_filter = NullNodeFilter.new)
|
18
|
+
next_node = nil
|
19
|
+
if NodeIterator.has_children?(node) then
|
20
|
+
next_node = node[0] # The index should be 1 according to the REXML docs
|
21
|
+
elsif node.next_sibling_node
|
22
|
+
next_node = node.next_sibling_node
|
23
|
+
elsif NodeIterator.has_parent_with_sibling?(node)
|
24
|
+
next_node = node.parent.next_sibling_node
|
25
|
+
end
|
26
|
+
return next_node if node_filter.accept(next_node) || next_node == nil
|
27
|
+
find_next_node(next_node, node_filter)
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
def initialize(node, node_filter = NullNodeFilter.new)
|
32
|
+
@node_filter = node_filter
|
33
|
+
@next_node = node
|
34
|
+
end
|
35
|
+
|
36
|
+
def has_next()
|
37
|
+
@next_node ? true : false
|
38
|
+
end
|
39
|
+
|
40
|
+
def next
|
41
|
+
node = @next_node
|
42
|
+
@next_node = NodeIterator.find_next_node(node, @node_filter)
|
43
|
+
node
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def NodeIterator.has_children?(node)
|
52
|
+
node.respond_to?(:[]) && node.respond_to?(:size) && node.size > 0
|
53
|
+
end
|
54
|
+
|
55
|
+
def NodeIterator.has_parent_with_sibling?(node)
|
56
|
+
node.parent && node.parent.next_sibling_node
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module REXML
|
2
|
+
|
3
|
+
# The REXML::NotationDecl mix-in adds methods that are useful for
|
4
|
+
# notation declarations, but not present in the standard
|
5
|
+
# REXML::NotationDecl class
|
6
|
+
class NotationDecl
|
7
|
+
|
8
|
+
# This method retrieves the name of the notation.
|
9
|
+
def name
|
10
|
+
@name
|
11
|
+
end
|
12
|
+
|
13
|
+
# This method retrieves the system identifier specified in the notation
|
14
|
+
# declaration. If there is no system identifier defined, the method returns
|
15
|
+
# +nil+
|
16
|
+
def system
|
17
|
+
parse_rest(@rest)[1]
|
18
|
+
end
|
19
|
+
|
20
|
+
# This method retrieves the public identifier specified in the notation
|
21
|
+
# declaration. If there is no public identifier defined, the method returns
|
22
|
+
# +nil+
|
23
|
+
def public
|
24
|
+
return nil unless @middle == "PUBLIC"
|
25
|
+
parse_rest(@rest)[0]
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def parse_rest(rest)
|
31
|
+
case rest
|
32
|
+
when /^"([^"]+)"\s+"([^"]+)"$/
|
33
|
+
return [$1,$2]
|
34
|
+
when /^'([^']+)'\s+'([^']+)'$/
|
35
|
+
return [$1,$2]
|
36
|
+
when /^"([^"]+)"\s+'([^']+)'$/
|
37
|
+
return [$1,$2]
|
38
|
+
when /^'([^']+)'\s+"([^"]+)"$/
|
39
|
+
return [$1,$2]
|
40
|
+
when /^"([^"]+)"$/
|
41
|
+
return [nil, $1] if @middle == 'SYSTEM'
|
42
|
+
return [$1, nil] if @middle == 'PUBLIC'
|
43
|
+
raise "Unknown notation keyword: #{@middle}"
|
44
|
+
when /^'([^']+)'$/
|
45
|
+
return [nil, $1] if @middle == 'SYSTEM'
|
46
|
+
return [$1, nil] if @middle == 'PUBLIC'
|
47
|
+
raise "Unknown notation keyword: #{@middle}"
|
48
|
+
else
|
49
|
+
raise "Could not parse \@rest variable in REXML::NotationDecl: |#{@rest}|"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
@@ -0,0 +1,163 @@
|
|
1
|
+
#! /usr/bin/ruby
|
2
|
+
|
3
|
+
require 'rexml/document'
|
4
|
+
require 'test/unit/xml/attributes_mixin' # Must be required after rexml/document
|
5
|
+
require 'test/unit/xml/doctype_mixin' # Must be required after rexml/document
|
6
|
+
require 'test/unit/xml/notationdecl_mixin' # Must be required after rexml/document
|
7
|
+
require 'test/unit'
|
8
|
+
require 'test/unit/xml/conditionals'
|
9
|
+
require 'test/unit/xml/xmlequalfilter'
|
10
|
+
require 'test/unit/xml/nodeiterator'
|
11
|
+
|
12
|
+
=begin rdoc
|
13
|
+
This module contains assertions about XML documents. The assertions are
|
14
|
+
meant to be mixed in to test classes such as Test::Unit::TestCase.
|
15
|
+
=end
|
16
|
+
module Test
|
17
|
+
module Unit
|
18
|
+
module XML
|
19
|
+
|
20
|
+
# This method checks whether two well-formed XML documents are equal.
|
21
|
+
# Two XML documents are considered equal if:
|
22
|
+
# * They contain the same type of nodes, in the same order,
|
23
|
+
# except for text nodes that are empty, or contain only
|
24
|
+
# whitespace. Such text nodes are ignored.
|
25
|
+
# * The corresponding nodes in the two documents are equal.
|
26
|
+
#
|
27
|
+
# Nodes are tested for equality as follows:
|
28
|
+
# XML Declarations::
|
29
|
+
# XML declarations are equal if they have the same version,
|
30
|
+
# encoding, and stand-alone pseudo-attributes.
|
31
|
+
# Doctype::
|
32
|
+
# Doctypes are equal if they fulfill all of the following conditions:
|
33
|
+
# * They have the same public identifier, or neither has a public identifier
|
34
|
+
# * If one of the doctypes has a system identifier that is a URN,
|
35
|
+
# the other doctype must have a system identifier that is the same URN.
|
36
|
+
# System identifiers that are URLs are ignored for comparison purposes.
|
37
|
+
# The reason is that the same DTD is very often stored in many different
|
38
|
+
# locations (for example different directories on different computers).
|
39
|
+
# Therefore the physical location of the DTD does not say anything useful
|
40
|
+
# about whether two documents are equal.
|
41
|
+
# * An entity declaration present in one of the doctype declarations
|
42
|
+
# must also be present in the other.
|
43
|
+
# * A notation declaration present in one of the doctype declarations
|
44
|
+
# must also be present in the other.
|
45
|
+
# Internal General Entity Declaration::
|
46
|
+
# Internal General entity declarations are equal if they have the same name,
|
47
|
+
# and the same value.
|
48
|
+
# External General Entity Declaration::
|
49
|
+
# External general entity declarations are equal if they have the same name,
|
50
|
+
# and if the identifiers are of the same type (PUBLIC or SYSTEM) and have
|
51
|
+
# the same value. Note that if the identifiers are URLs, a comparison may
|
52
|
+
# fail even though both URLS point to the same resource, for example if one
|
53
|
+
# URL is relative and the other is absolute.
|
54
|
+
# Notation Declaration::
|
55
|
+
# Notation declarations are equal if they have the same name,
|
56
|
+
# and if the identifiers are of the same type (PUBLIC or SYSTEM) and have
|
57
|
+
# the same value.
|
58
|
+
# Elements::
|
59
|
+
# Elements are considered equal if they have the same generic
|
60
|
+
# identifier (tag name), belong to the same namespace, and have the same
|
61
|
+
# attributes. Note that the namespace _prefixes_ of two elements may be different
|
62
|
+
# as long as they belong to the same namespace.
|
63
|
+
# Attributes::
|
64
|
+
# Attributes are equal if they belong to the same namespace,
|
65
|
+
# have the same name, and the same value.
|
66
|
+
# Namespace Declarations::
|
67
|
+
# Namespace _declarations_ (attributes named <tt>xmlns:<em>prefix</em></tt>)
|
68
|
+
# are ignored. There are several reasons for this:
|
69
|
+
# - As long as two elements or attributes
|
70
|
+
# belong to the same namespace, it does not matter what prefixes
|
71
|
+
# are used. XML processors may also change prefixes in unpredictable
|
72
|
+
# ways without this being an error.
|
73
|
+
# - XML processors may _move_ namespace
|
74
|
+
# declarations from one element to another (usually an ancestor,
|
75
|
+
# sometimes a descendant) without this being an error, or under
|
76
|
+
# control by the programmer.
|
77
|
+
# - XML processors may _add_ extraneous namespace declarations
|
78
|
+
# in a manner that is hard for programmers to control.
|
79
|
+
# Processing Instructions::
|
80
|
+
# Processing instructions are considered equal if the string
|
81
|
+
# values of their targets and contents are equal.
|
82
|
+
# Text::
|
83
|
+
# Text nodes are equal if their values are equal. However, empty
|
84
|
+
# text nodes, and text nodes containing only whitespace are ignored.
|
85
|
+
# CDATA::
|
86
|
+
# CDATA nodes are equal if their text content is equal. Whitespace
|
87
|
+
# is _not_ normalized.
|
88
|
+
# Comments::
|
89
|
+
# Comments are equal if they have the same content.
|
90
|
+
#
|
91
|
+
# The +expected_doc+ and +actual_doc+ arguments to this method may be of
|
92
|
+
# the following types:
|
93
|
+
# * A +REXML+ node, usually a <tt>REXML::Document</tt> or <tt>REXML::Element</tt>
|
94
|
+
# * A +File+ or other +IO+ object representing an XML document
|
95
|
+
# * A string containing an XML document
|
96
|
+
def assert_xml_equal(expected_doc, actual_doc, message = nil)
|
97
|
+
expected_doc = parse_xml(expected_doc)
|
98
|
+
actual_doc = parse_xml(actual_doc)
|
99
|
+
_wrap_assertion do
|
100
|
+
full_message = build_message(message, <<EOT, actual_doc.inspect, expected_doc.inspect)
|
101
|
+
|
102
|
+
<?> expected to be equal to
|
103
|
+
<?> but was not.
|
104
|
+
EOT
|
105
|
+
assert_block(full_message){are_equal?(expected_doc, actual_doc)}
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
|
110
|
+
# This method compares two XML documents and returns +true+ if they are
|
111
|
+
# _not_ equal, +false+ otherwise. This is the inverse of assert_xml_equal.
|
112
|
+
def assert_xml_not_equal(expected_doc, actual_doc, message = nil)
|
113
|
+
expected_doc = parse_xml(expected_doc)
|
114
|
+
actual_doc = parse_xml(actual_doc)
|
115
|
+
_wrap_assertion do
|
116
|
+
full_message = build_message(message, <<EOT, actual_doc.inspect, expected_doc.inspect)
|
117
|
+
|
118
|
+
<?> expected not to be equal to
|
119
|
+
<?> but was equal.
|
120
|
+
EOT
|
121
|
+
assert_block(full_message){ ! are_equal?(expected_doc, actual_doc)}
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
|
126
|
+
private
|
127
|
+
|
128
|
+
def parse_xml(xml)
|
129
|
+
case xml
|
130
|
+
when IO
|
131
|
+
REXML::Document.new(xml)
|
132
|
+
when String
|
133
|
+
REXML::Document.new(xml)
|
134
|
+
else
|
135
|
+
xml
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def are_equal?(expected_doc, actual_doc)
|
140
|
+
comparator = Conditionals.create
|
141
|
+
iterate(expected_doc, actual_doc) do |expected_node, actual_node|
|
142
|
+
unless comparator.compare_xml_nodes(expected_node, actual_node)
|
143
|
+
return false
|
144
|
+
end
|
145
|
+
end
|
146
|
+
true
|
147
|
+
end
|
148
|
+
|
149
|
+
def iterate(expected_doc, actual_doc)
|
150
|
+
filter = Test::Unit::XML::XmlEqualFilter.new()
|
151
|
+
expected_iterator = NodeIterator.new(expected_doc, filter)
|
152
|
+
actual_iterator = NodeIterator.new(actual_doc, filter)
|
153
|
+
while expected_iterator.has_next()
|
154
|
+
expected_node = expected_iterator.next()
|
155
|
+
actual_node = actual_iterator.next()
|
156
|
+
yield expected_node, actual_node
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
@@ -0,0 +1,31 @@
|
|
1
|
+
#! /usr/bin/ruby
|
2
|
+
|
3
|
+
module Test
|
4
|
+
module Unit
|
5
|
+
module XML
|
6
|
+
|
7
|
+
# This filter class accepts any node except text nodes
|
8
|
+
# that contain non-significant whitespace
|
9
|
+
class XmlEqualFilter
|
10
|
+
def accept(node)
|
11
|
+
case
|
12
|
+
when node.kind_of?(REXML::Text)
|
13
|
+
is_significant?(node.value)
|
14
|
+
when node.kind_of?(REXML::Entity)
|
15
|
+
false
|
16
|
+
when node.kind_of?(REXML::NotationDecl)
|
17
|
+
false
|
18
|
+
else
|
19
|
+
true
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def is_significant?(string)
|
26
|
+
string =~ /^\s*$/ ? false : true
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
metadata
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mezza-testunitxml
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.1.6
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- "Henrik M\xC3\xA5rtensson"
|
9
|
+
- Merul Patel
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
|
14
|
+
date: 2011-06-02 00:00:00 +01:00
|
15
|
+
default_executable:
|
16
|
+
dependencies: []
|
17
|
+
|
18
|
+
description:
|
19
|
+
email:
|
20
|
+
- dag.henrik.martensson@gmail.com
|
21
|
+
- merul.patel@gmail.com
|
22
|
+
executables: []
|
23
|
+
|
24
|
+
extensions: []
|
25
|
+
|
26
|
+
extra_rdoc_files: []
|
27
|
+
|
28
|
+
files:
|
29
|
+
- lib/test/unit/xml/attributes_mixin.rb
|
30
|
+
- lib/test/unit/xml/conditionals.rb
|
31
|
+
- lib/test/unit/xml/doctype_mixin.rb
|
32
|
+
- lib/test/unit/xml/nodeiterator.rb
|
33
|
+
- lib/test/unit/xml/notationdecl_mixin.rb
|
34
|
+
- lib/test/unit/xml/xml_assertions.rb
|
35
|
+
- lib/test/unit/xml/xmlequalfilter.rb
|
36
|
+
- lib/test/unit/xml.rb
|
37
|
+
has_rdoc: true
|
38
|
+
homepage: https://github.com/mezza/testunitxml
|
39
|
+
licenses: []
|
40
|
+
|
41
|
+
post_install_message:
|
42
|
+
rdoc_options: []
|
43
|
+
|
44
|
+
require_paths:
|
45
|
+
- lib
|
46
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
47
|
+
none: false
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: 1.8.6
|
52
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
requirements: []
|
59
|
+
|
60
|
+
rubyforge_project:
|
61
|
+
rubygems_version: 1.5.2
|
62
|
+
signing_key:
|
63
|
+
specification_version: 3
|
64
|
+
summary: testunitxml extends the Test::Unit framework with an assertion for testing well-formed XML documents.
|
65
|
+
test_files: []
|
66
|
+
|