rubyjedi-testunitxml 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES ADDED
@@ -0,0 +1,19 @@
1
+ = Changes
2
+
3
+ == Version 0.1.5
4
+
5
+ * Fixed a bug when comparing attributes containing entity references.
6
+ * Added an <tt>assert_xml_not_equal</tt> method.
7
+
8
+ == Version 0.1.4
9
+
10
+ * Added support for Doctype comparisons in +assert_xml_equal+
11
+ * Added <tt>setup.rb</tt> file to distribution packages
12
+ * Added installation section to README file
13
+ * Added links to online tutorial to README file
14
+ * Added CHANGES file
15
+
16
+
17
+ == Version 0.1.3
18
+
19
+ The initial release.
data/MIT-LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ = MIT-LICENSE
2
+
3
+ Copyright � 2006 Henrik M�rtensson
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a
6
+ copy of this software and associated documentation files (the "Software"),
7
+ to deal in the Software without restriction, including without limitation
8
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
9
+ and/or sell copies of the Software, and to permit persons to whom the
10
+ Software is furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21
+ IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,119 @@
1
+ = Test::Unit::XML
2
+ == An XML Test Framework
3
+
4
+ Version: 0.1.5
5
+
6
+ Author: Henrik M�rtensson
7
+
8
+ (c) 2006 by Henrik M�rtensson
9
+
10
+ == Introduction
11
+
12
+ Test::Unit::XML extends the Test::Unit framework with
13
+ an assertion for testing well-formed XML documents.
14
+
15
+ Using Test::Unit::XML is easy. All you have to do is to
16
+ require +testunitxml+, and you will then have an
17
+ +assert_xml_equal+ assertion available in the
18
+ Test::Unit::TestCase class.
19
+
20
+ In addition to the API documentation included in the package, you can get information about how
21
+ to use Test::Unit::XML from the following sources:
22
+
23
+ * The online tutorial[http://kallokain.blogspot.com/2006/01/testunitxml-quick-start-tutorial.html] at
24
+ the Kallokain[http://kallokain.blogspot.com/] blog.
25
+ * The {test cases}[link:../../test/] included in the distribution package.
26
+
27
+ == Installation
28
+
29
+ === Install Using the +RubyGem+ Package Manager
30
+
31
+ The easiest way to install Test::Unit::XML is to make a remote installation via the RubyGem
32
+ package manager:
33
+
34
+ <tt>gem install testunitxml</tt>
35
+
36
+ If you have downloaded a gem package from Rubyforge, you can do a local installation:
37
+
38
+ <tt>cd <em>download_directory_path</em></tt>
39
+
40
+ <tt>gem install testunitxml -l</tt>
41
+
42
+ === Install from a Zip file or Tarball
43
+
44
+ If you do not have RubyGem installed, you can download a Zip file or tarball and install
45
+ from it instead:
46
+
47
+ 1:: Unpack the Zip or tarball archive.
48
+ 2:: cd to the directory you just unpacked.
49
+ 3:: Run the command:
50
+ <tt>ruby setup.rb install</tt>
51
+
52
+
53
+
54
+ == What Does _Equal_ XML Documents Mean?
55
+
56
+ It is hard to define exactly what _equal_ means in the
57
+ context of XML documents. I have tried to follow W3C
58
+ XML recommendations as far as possible. There are a
59
+ few things worthy of note:
60
+
61
+ * Namespace _declarations_, i.e. attributes that declare
62
+ namespaces, are ignored for comparison purposes. (The
63
+ namespaces _are_ used in comparisons.) The reason is
64
+ that XML processors may move the declarations from one
65
+ element to another, or change prefixes in ways that
66
+ cannot be directly controlled by a programmer. For
67
+ example, two different XSLT processors could use
68
+ the same stylesheet and produce XML documents that use
69
+ different namespace prefixes, and have declarations
70
+ on different elements, but are still considered equal.
71
+
72
+ * Text nodes that are empty or contain only whitespace
73
+ are ignored for comparison purposes. This makes it
74
+ easier to test output from various transformation
75
+ engines. These often produce extraneous whitespace.
76
+
77
+ == The Future
78
+
79
+ There are a few things in the pipeline:
80
+
81
+ * assert_xml_equal_structure - checks that the structure
82
+ of two documents are equal, but ignores content, attributes,
83
+ processing istructions, comments, CDATA, and doctype
84
+ declarations.
85
+ * assert_xml_similar - Like assert_xml_equal, but ignores the
86
+ order of child elements.
87
+ * Configurability. It _might_ be useful to be able to set
88
+ configuration options for testing. I'll have to think a
89
+ bit about this though.
90
+ * Document difference functions, like the Java XMLUnit test
91
+ suite.
92
+
93
+ I plan to implement these features as I need them in other
94
+ projects, so there is no time plan, and no guarantee as to the
95
+ order in which I'll implement anything.
96
+
97
+ == License
98
+
99
+ See the {MIT-LICENSE}[link:files/MIT-LICENSE.html] file.
100
+
101
+ == Contact
102
+
103
+ You can email bug reports, opinions and questions to
104
+ mailto:self@henrikmartensson.org. You may also wish to visit
105
+ my home page, www.henrikmartensson.org, for more information
106
+ about Test::Unit::XML and other projects. I will write about
107
+ Test::Unit::XML at the the Kallokain[http://kallokain.blogspot.com/]
108
+ blog. You are welcome to visit, and comment.
109
+
110
+ If you find Test::Unit::XML useful, please do tell me about it. I would like
111
+ to list projects that use it on the {Test::Unit::XML web site}[http://testunitxml.rubyforge.org/].
112
+
113
+ If you find Test::Unit::XML lacking in some respect, or buggy,
114
+ I am even more interested. I can't fix bugs I do not know about.
115
+
116
+ Finally, if you write about Test::Unit::XML, I'd like to link to
117
+ the article on my web site, or at least mention it if you write
118
+ for a magazine, so please tell me.
119
+
@@ -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,147 @@
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
+ #puts "Conditionals, Expected: #{expected_node.class} : #{expected_node.name}"
26
+ #puts "Conditionals, Expected: #{actual_node.class} : #{actual_node.name}"
27
+ return false unless actual_node.instance_of? expected_node.class
28
+ return false if expected_node == nil && actual_node != nil
29
+ return false if expected_node != nil && actual_node == nil
30
+ #puts "actual_node is nil" unless actual_node
31
+ #puts "expected_node is nil" unless expected_node
32
+ case actual_node
33
+ when REXML::Document
34
+ # TODO: Implement Document comparison
35
+ true
36
+ when REXML::DocType
37
+ compare_doctypes(expected_node, actual_node)
38
+ when REXML::Element
39
+ compare_elements(expected_node, actual_node)
40
+ when REXML::CData
41
+ compare_texts(expected_node, actual_node)
42
+ when REXML::Text
43
+ compare_texts(expected_node, actual_node)
44
+ when REXML::Comment
45
+ compare_comments(expected_node, actual_node)
46
+ when REXML::Instruction
47
+ compare_pi(expected_node, actual_node)
48
+ when REXML::XMLDecl
49
+ compare_xml_declaration(expected_node, actual_node)
50
+ #when REXML::Entity
51
+ # compare_xml_entities(expected_node, actual_node)
52
+ else
53
+ puts "Unknown node type #{actual_node.class}"
54
+ false
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ def compare_doctypes(expected_node, actual_node)
61
+ return compare_system_id(expected_node.system, actual_node.system) &&
62
+ expected_node.public == actual_node.public &&
63
+ compare_xml_internal_dtd_subset(expected_node, actual_node)
64
+ end
65
+
66
+ def compare_system_id(expected_id, actual_id)
67
+ is_expected_urn = expected_id =~ /^urn:/i
68
+ is_actual_urn = actual_id =~ /^urn:/i
69
+ if is_expected_urn || is_actual_urn
70
+ expected_id == actual_id
71
+ else
72
+ true
73
+ end
74
+ end
75
+
76
+ def compare_elements(expected_node, actual_node)
77
+ return expected_node.name == actual_node.name &&
78
+ expected_node.namespace() == actual_node.namespace() &&
79
+ compare_attributes(expected_node.attributes, actual_node.attributes)
80
+ end
81
+
82
+ def compare_attributes(expected_attributes, actual_attributes)
83
+ return false unless attribute_count(expected_attributes) == attribute_count(actual_attributes)
84
+ expected_attributes.each_attribute do |expected_attribute|
85
+ expected_prefix = expected_attribute.prefix()
86
+ unless expected_prefix == 'xmlns' then
87
+ expected_name = expected_attribute.name
88
+ expected_namespace = expected_attribute.namespace
89
+ actual_attribute = actual_attributes.get_attribute_ns(expected_namespace, expected_name)
90
+ return false unless actual_attribute
91
+ return false if expected_attribute.value() != actual_attribute.value()
92
+ end
93
+ end
94
+ true
95
+ end
96
+
97
+ def attribute_count(attributes)
98
+ # Do not count namespace declarations
99
+ attributes.size - attributes.prefixes.size
100
+ end
101
+
102
+ def compare_texts(expected_node, actual_node)
103
+ expected_node.value.eql?(actual_node.value)
104
+ end
105
+
106
+ def compare_comments(expected_node, actual_node)
107
+ expected_node == actual_node
108
+ end
109
+
110
+ def compare_pi(expected_pi, actual_pi)
111
+ return expected_pi.target == actual_pi.target &&
112
+ expected_pi.content == actual_pi.content
113
+ end
114
+
115
+ def compare_xml_declaration(expected_decl, actual_decl)
116
+ return expected_decl == actual_decl
117
+ end
118
+
119
+ def compare_xml_internal_dtd_subset(expected_node, actual_node)
120
+ expected_subset = expected_node.children()
121
+ actual_subset = actual_node.children()
122
+ return false unless expected_subset.length == actual_subset.length
123
+ expected_subset.inject(true) { |memo, expected_decl|
124
+ case expected_decl
125
+ when REXML::Entity
126
+ memo &&
127
+ expected_decl.value == actual_node.entities[expected_decl.name].value &&
128
+ expected_decl.ndata == actual_node.entities[expected_decl.name].ndata
129
+ when REXML::NotationDecl
130
+ actual_notation_decl = actual_node.notation(expected_decl.name)
131
+ memo &&
132
+ actual_notation_decl != nil &&
133
+ expected_decl.name == actual_notation_decl.name &&
134
+ expected_decl.public == actual_notation_decl.public &&
135
+ expected_decl.system == actual_notation_decl.system
136
+ when REXML::Comment
137
+ true
138
+ else
139
+ raise "Unexpected node type in internal DTD subset of expected document: " + expected_decl.inspect
140
+ end
141
+ }
142
+ end
143
+
144
+ end
145
+ end
146
+ end
147
+ 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,67 @@
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
+ #puts "In NodeIterator: #{node.class}"
19
+ #puts " has_children: #{NodeIterator.has_children?(node)}"
20
+ #puts " next_sibling_node: #{node.next_sibling_node}"
21
+ #puts " has_parent_with_sibling?: #{NodeIterator.has_parent_with_sibling?(node)}"
22
+ #node.write if node.respond_to?(:name) && node.name == 'TestThing'
23
+ return nil unless node
24
+ next_node = nil
25
+ if NodeIterator.has_children?(node) then
26
+ next_node = node[0] # The index should be 1 according to the REXML docs
27
+ elsif node.next_sibling_node
28
+ next_node = node.next_sibling_node
29
+ elsif NodeIterator.has_parent_with_sibling?(node)
30
+ next_node = node.parent.next_sibling_node
31
+ end
32
+ return next_node if node_filter.accept(next_node) || next_node == nil
33
+ find_next_node(next_node, node_filter)
34
+ end
35
+
36
+
37
+ def initialize(node, node_filter = NullNodeFilter.new)
38
+ @node_filter = node_filter
39
+ @next_node = node
40
+ end
41
+
42
+ def has_next()
43
+ @next_node ? true : false
44
+ end
45
+
46
+ def next
47
+ node = @next_node
48
+ @next_node = NodeIterator.find_next_node(node, @node_filter)
49
+ node
50
+ end
51
+
52
+
53
+
54
+
55
+ private
56
+
57
+ def NodeIterator.has_children?(node)
58
+ node.respond_to?(:[]) && node.respond_to?(:size) && node.size > 0
59
+ end
60
+
61
+ def NodeIterator.has_parent_with_sibling?(node)
62
+ node.parent && node.parent.next_sibling_node
63
+ end
64
+ end
65
+ end
66
+ end
67
+ 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
+