xqsr3-xml 0.1.0.1
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.
- checksums.yaml +7 -0
- data/LICENSE +29 -0
- data/README.md +60 -0
- data/lib/xqsr3/xml/utilities/compare.rb +544 -0
- data/lib/xqsr3/xml/utilities/navigation.rb +108 -0
- data/lib/xqsr3/xml/version.rb +71 -0
- data/test/unit/tc_version.rb +36 -0
- data/test/unit/ts_all.rb +12 -0
- data/test/unit/xml/ts_all.rb +12 -0
- data/test/unit/xml/utilities/tc_compare.rb +256 -0
- data/test/unit/xml/utilities/tc_navigation.rb +55 -0
- data/test/unit/xml/utilities/ts_all.rb +12 -0
- metadata +94 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 1995665f234ee13f105bf6316a5ff88c91d49a22
|
|
4
|
+
data.tar.gz: f75620b304904ff142f92ef8576cc32b7ce1bba1
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 9719a1c7e803abf401646f4934d06231ff06cb0f371921d1cae3e442fd7408d7197e0ea3bafa03524f230a71638ff7f2ded0beabdfb449befe7e31c3aff0ed76
|
|
7
|
+
data.tar.gz: 9fad44e02ea4784441a2e170f476e7f593799339354ab05d7cb861b89c355b8d1a376c7b3b345457a1c69f408e6c10b146da60e90107140abbad9fc39d82e01f
|
data/LICENSE
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
xqsr3-xml
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2005-2016, Matthew Wilson and Synesis Software
|
|
4
|
+
All rights reserved.
|
|
5
|
+
|
|
6
|
+
Redistribution and use in source and binary forms, with or without
|
|
7
|
+
modification, are permitted provided that the following conditions are met:
|
|
8
|
+
|
|
9
|
+
* Redistributions of source code must retain the above copyright notice, this
|
|
10
|
+
list of conditions and the following disclaimer.
|
|
11
|
+
|
|
12
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
|
13
|
+
this list of conditions and the following disclaimer in the documentation
|
|
14
|
+
and/or other materials provided with the distribution.
|
|
15
|
+
|
|
16
|
+
* Neither the names of xqsr3 and xqsr3-xml nor the names of its
|
|
17
|
+
contributors may be used to endorse or promote products derived from
|
|
18
|
+
this software without specific prior written permission.
|
|
19
|
+
|
|
20
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
21
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
22
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
23
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
24
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
25
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
26
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
27
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
28
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
29
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# xqsr3-xml
|
|
2
|
+
e**X**tensions by fine **Q**uantum for **S**tandard **R**uby and **3**rd-party libraries, for **XML**
|
|
3
|
+
|
|
4
|
+
[](https://badge.fury.io/rb/xqsr3-xml)
|
|
5
|
+
|
|
6
|
+
## Introduction
|
|
7
|
+
|
|
8
|
+
[**xqsr3**](https://github.com/synesissoftware/xqsr3/) is a lightweight, low-coupling library of assorted extensions to standard ruby and 3rd-party libraries. As of version **0.31** of **xqsr3**, the **XML Utilites** components were moved out into **xqsr3-xml** in order that the core **xqsr** can be independent of any non-standard libraries.
|
|
9
|
+
|
|
10
|
+
## Table of Contents
|
|
11
|
+
|
|
12
|
+
1. [Introduction](#introduction)
|
|
13
|
+
2. [Installation](#installation)
|
|
14
|
+
3. [Components](#components)
|
|
15
|
+
4. [Project Information](#project-information)
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
Install using `gem install xqsr3-xml` or add it to your `Gemfile`.
|
|
20
|
+
|
|
21
|
+
## Components
|
|
22
|
+
|
|
23
|
+
**xqsr3** provides components in the following categories:
|
|
24
|
+
|
|
25
|
+
* Array Utilities
|
|
26
|
+
* Command-line Utilities
|
|
27
|
+
* Containers
|
|
28
|
+
* Conversion
|
|
29
|
+
* Diagnostics
|
|
30
|
+
* Hash Utilities
|
|
31
|
+
* IO
|
|
32
|
+
* Quality
|
|
33
|
+
* String Utilities
|
|
34
|
+
|
|
35
|
+
**xqsr3-xml** provides components in the following categories:
|
|
36
|
+
|
|
37
|
+
* XML Utilities
|
|
38
|
+
|
|
39
|
+
## Project Information
|
|
40
|
+
|
|
41
|
+
### Where to get help
|
|
42
|
+
|
|
43
|
+
[GitHub Page](https://github.com/synesissoftware/xqsr3-xml "GitHub Page")
|
|
44
|
+
|
|
45
|
+
### Contribution guidelines
|
|
46
|
+
|
|
47
|
+
Defect reports, feature requests, and pull requests are welcome on https://github.com/synesissoftware/xqsr3-xml.
|
|
48
|
+
|
|
49
|
+
### Dependencies
|
|
50
|
+
|
|
51
|
+
* [**Nokogiri**](http://nokogiri.org/)
|
|
52
|
+
* [**xqsr3**](https://github.com/synesissoftware/xqsr3/)
|
|
53
|
+
|
|
54
|
+
### Related projects
|
|
55
|
+
|
|
56
|
+
* [**xqsr3**](https://github.com/synesissoftware/xqsr3/)
|
|
57
|
+
|
|
58
|
+
### License
|
|
59
|
+
|
|
60
|
+
**xqsr3-xml** is released under the 3-clause BSD license. See [LICENSE](./LICENSE) for details.
|
|
@@ -0,0 +1,544 @@
|
|
|
1
|
+
|
|
2
|
+
# ######################################################################## #
|
|
3
|
+
# File: lib/xqsr3/xml/_utilities/compare.rb
|
|
4
|
+
#
|
|
5
|
+
# Purpose: Definition of the ::Xqsr3::XML::Utilities::Compare
|
|
6
|
+
# module
|
|
7
|
+
#
|
|
8
|
+
# Created: 30th July 2017
|
|
9
|
+
# Updated: 16th August 2018
|
|
10
|
+
#
|
|
11
|
+
# Home: http://github.com/synesissoftware/xqsr3
|
|
12
|
+
#
|
|
13
|
+
# Author: Matthew Wilson
|
|
14
|
+
#
|
|
15
|
+
# Copyright (c) 2017-2018, Matthew Wilson and Synesis Software
|
|
16
|
+
# All rights reserved.
|
|
17
|
+
#
|
|
18
|
+
# Redistribution and use in source and binary forms, with or without
|
|
19
|
+
# modification, are permitted provided that the following conditions are
|
|
20
|
+
# met:
|
|
21
|
+
#
|
|
22
|
+
# * Redistributions of source code must retain the above copyright notice,
|
|
23
|
+
# this list of conditions and the following disclaimer.
|
|
24
|
+
#
|
|
25
|
+
# * Redistributions in binary form must reproduce the above copyright
|
|
26
|
+
# notice, this list of conditions and the following disclaimer in the
|
|
27
|
+
# documentation and/or other materials provided with the distribution.
|
|
28
|
+
#
|
|
29
|
+
# * Neither the names of the copyright holder nor the names of its
|
|
30
|
+
# contributors may be used to endorse or promote products derived from
|
|
31
|
+
# this software without specific prior written permission.
|
|
32
|
+
#
|
|
33
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
|
34
|
+
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
|
35
|
+
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
36
|
+
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
|
37
|
+
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
38
|
+
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
39
|
+
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
40
|
+
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
41
|
+
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
42
|
+
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
43
|
+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
44
|
+
#
|
|
45
|
+
# ######################################################################## #
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
# ##########################################################
|
|
49
|
+
# ::Xqsr3::XML::Utilities::Compare
|
|
50
|
+
|
|
51
|
+
=begin
|
|
52
|
+
=end
|
|
53
|
+
|
|
54
|
+
require 'xqsr3/xml/utilities/navigation'
|
|
55
|
+
|
|
56
|
+
require 'xqsr3/quality/parameter_checking'
|
|
57
|
+
|
|
58
|
+
require 'nokogiri'
|
|
59
|
+
|
|
60
|
+
module Xqsr3
|
|
61
|
+
module XML
|
|
62
|
+
module Utilities
|
|
63
|
+
|
|
64
|
+
module Compare
|
|
65
|
+
|
|
66
|
+
# Class that represents the result of an XML comparison
|
|
67
|
+
#
|
|
68
|
+
# NOTE: Sadly, we cannot create instances of +FalseClass+/+TrueClass+,
|
|
69
|
+
# to which we could then add a +reason+ attribute, so instead we must
|
|
70
|
+
# have a results class
|
|
71
|
+
class Result
|
|
72
|
+
|
|
73
|
+
include ::Xqsr3::Quality::ParameterChecking
|
|
74
|
+
|
|
75
|
+
protected :check_parameter
|
|
76
|
+
|
|
77
|
+
#
|
|
78
|
+
# Options:
|
|
79
|
+
#
|
|
80
|
+
# +:different_attributes+
|
|
81
|
+
# +:different_attribute_count+
|
|
82
|
+
# +:different_attribute_order+
|
|
83
|
+
# +:different_child_node_count+
|
|
84
|
+
# +:different_child_node_order+
|
|
85
|
+
# +:different_child_nodes+
|
|
86
|
+
# +:different_node_names+
|
|
87
|
+
# +:different_node_contents+
|
|
88
|
+
# +:parameter_is_empty+
|
|
89
|
+
# +:parameter_is_nil+
|
|
90
|
+
# +:+
|
|
91
|
+
|
|
92
|
+
def initialize status, reason, **options
|
|
93
|
+
|
|
94
|
+
@call_stack = caller(2)
|
|
95
|
+
|
|
96
|
+
check_parameter status, 'status', types: [ ::FalseClass, ::TrueClass ]
|
|
97
|
+
check_parameter reason, 'reason', type: ::Symbol, allow_nil: true
|
|
98
|
+
|
|
99
|
+
@status = status
|
|
100
|
+
@reason = reason
|
|
101
|
+
|
|
102
|
+
@lhs_node = options[:lhs_node]
|
|
103
|
+
@rhs_node = options[:rhs_node]
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def self.return status, reason, **options
|
|
107
|
+
|
|
108
|
+
return self.new status, reason, **options
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def self.same reason = nil, **options
|
|
112
|
+
|
|
113
|
+
return self.new true, reason, **options
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def self.different reason, **options
|
|
117
|
+
|
|
118
|
+
return self.new false, reason, **options
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
attr_reader :call_stack
|
|
122
|
+
attr_reader :status
|
|
123
|
+
attr_reader :reason
|
|
124
|
+
|
|
125
|
+
def different?
|
|
126
|
+
|
|
127
|
+
!status
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def same?
|
|
131
|
+
|
|
132
|
+
status
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def details
|
|
136
|
+
|
|
137
|
+
r = reason.to_s.gsub(/_/, ' ')
|
|
138
|
+
|
|
139
|
+
qualifying = ''
|
|
140
|
+
|
|
141
|
+
if @lhs_node
|
|
142
|
+
|
|
143
|
+
qualifying += '; ' unless qualifying.empty?
|
|
144
|
+
qualifying += "lhs-node=#{@lhs_node}"
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
if @rhs_node
|
|
148
|
+
|
|
149
|
+
qualifying += '; ' unless qualifying.empty?
|
|
150
|
+
qualifying += "rhs-node=#{@rhs_node}"
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
r = "#{r}: #{qualifying}" unless qualifying.empty?
|
|
154
|
+
|
|
155
|
+
r
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def to_s
|
|
159
|
+
|
|
160
|
+
return 'same' if same?
|
|
161
|
+
|
|
162
|
+
"different, because: #{details}"
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
module Internal_Compare_
|
|
167
|
+
|
|
168
|
+
include ::Xqsr3::XML::Utilities::Navigation
|
|
169
|
+
|
|
170
|
+
extend ::Xqsr3::Quality::ParameterChecking
|
|
171
|
+
|
|
172
|
+
DEFAULT_OPTIONS = {
|
|
173
|
+
|
|
174
|
+
debug: false,
|
|
175
|
+
# element_order: false,
|
|
176
|
+
equate_nil_and_empty: false,
|
|
177
|
+
ignore_attributes: false,
|
|
178
|
+
ignore_attribute_order: true,
|
|
179
|
+
ignore_child_node_order: true,
|
|
180
|
+
ignore_content: false,
|
|
181
|
+
ignore_content_case: false,
|
|
182
|
+
ignore_xml_declarations: true,
|
|
183
|
+
normalise_whitespace: true,
|
|
184
|
+
# normalize_whitespace: true,
|
|
185
|
+
validate_params: true,
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
ORDER_OPTIONS_SYMBOLS = [
|
|
189
|
+
|
|
190
|
+
:element_order,
|
|
191
|
+
:ignore_attribute_order,
|
|
192
|
+
:ignore_child_node_order,
|
|
193
|
+
:ignore_content,
|
|
194
|
+
:ignore_content_case,
|
|
195
|
+
]
|
|
196
|
+
|
|
197
|
+
WHITESPACE_OPTIONS_SYMBOLS = [
|
|
198
|
+
|
|
199
|
+
:normalise_whitespace,
|
|
200
|
+
:normalize_whitespace,
|
|
201
|
+
]
|
|
202
|
+
|
|
203
|
+
def self.derive_options_ given_options
|
|
204
|
+
|
|
205
|
+
default_options = DEFAULT_OPTIONS
|
|
206
|
+
derived_options = {}.merge given_options
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
# sort whitespace
|
|
210
|
+
|
|
211
|
+
if WHITESPACE_OPTIONS_SYMBOLS.any? { |sym| given_options.has_key? sym }
|
|
212
|
+
|
|
213
|
+
default_options = default_options.reject { |k, v| WHITESPACE_OPTIONS_SYMBOLS.include? k }
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
if given_options.has_key? :normalise_whitespace
|
|
217
|
+
|
|
218
|
+
derived_options.delete :normalize_whitespace
|
|
219
|
+
elsif given_options.has_key? :normalize_whitespace
|
|
220
|
+
|
|
221
|
+
derived_options[:normalise_whitespace] = given_options[:normalize_whitespace]
|
|
222
|
+
|
|
223
|
+
derived_options.delete :normalize_whitespace
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
# sort element-order
|
|
228
|
+
|
|
229
|
+
if ORDER_OPTIONS_SYMBOLS.any? { |sym| given_options.has_key? sym }
|
|
230
|
+
|
|
231
|
+
default_options = default_options.reject { |k, v| ORDER_OPTIONS_SYMBOLS.include? k }
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
if given_options.has_key? :element_order
|
|
235
|
+
|
|
236
|
+
element_order = given_options[:element_order]
|
|
237
|
+
|
|
238
|
+
derived_options[:ignore_attribute_order] = !element_order
|
|
239
|
+
derived_options[:ignore_child_node_order] = !element_order
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
derived_options[:ignore_attribute_order] = given_options[:ignore_attribute_order] if given_options.has_key? :ignore_attribute_order
|
|
243
|
+
derived_options[:ignore_child_node_order] = given_options[:ignore_child_node_order] if given_options.has_key? :ignore_child_node_order
|
|
244
|
+
|
|
245
|
+
default_options.merge derived_options
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
def self.one_line_ s
|
|
249
|
+
|
|
250
|
+
s = s.to_s.gsub(/\s+/, ' ')
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
#
|
|
254
|
+
# +:debug+
|
|
255
|
+
# +:element_order+
|
|
256
|
+
# +:equate_nil_and_empty+
|
|
257
|
+
# +:ignore_attributes+
|
|
258
|
+
# +:ignore_attribute_order+
|
|
259
|
+
# +:ignore_xml_declarations+
|
|
260
|
+
# +:normalise_whitespace+
|
|
261
|
+
# +:normalize_whitespace+
|
|
262
|
+
# +:validate_params+
|
|
263
|
+
#
|
|
264
|
+
|
|
265
|
+
def self.xml_compare_ lhs, rhs, options
|
|
266
|
+
|
|
267
|
+
$stderr.puts "#{self}#{__method__}(lhs (#{lhs.class})=#{self.one_line_ lhs}, rhs (#{rhs.class})=#{self.one_line_ rhs}, options (#{options.class})=#{options})" if $DEBUG
|
|
268
|
+
|
|
269
|
+
# validate parameter(s)
|
|
270
|
+
|
|
271
|
+
check_parameter options, 'options', type: ::Hash if $DEBUG
|
|
272
|
+
|
|
273
|
+
validate_params = $DEBUG || options[:debug] || options[:validate_params]
|
|
274
|
+
|
|
275
|
+
check_parameter lhs, 'lhs', types: [ ::String, ::Nokogiri::XML::Node ], allow_nil: true if validate_params
|
|
276
|
+
check_parameter rhs, 'rhs', types: [ ::String, ::Nokogiri::XML::Node ], allow_nil: true if validate_params
|
|
277
|
+
|
|
278
|
+
options = self.derive_options_ options
|
|
279
|
+
|
|
280
|
+
# deal with nil(s)
|
|
281
|
+
|
|
282
|
+
return Result.same if lhs.nil? && rhs.nil?
|
|
283
|
+
|
|
284
|
+
if lhs.nil?
|
|
285
|
+
|
|
286
|
+
return Result.same if options[:equate_nil_and_empty] && ::String === rhs && rhs.empty?
|
|
287
|
+
|
|
288
|
+
return Result.different :parameter_is_nil
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
if rhs.nil?
|
|
292
|
+
|
|
293
|
+
return Result.same if options[:equate_nil_and_empty] && ::String === lhs && lhs.empty?
|
|
294
|
+
|
|
295
|
+
return Result.different :parameter_is_nil
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
# deal with string(s)
|
|
300
|
+
|
|
301
|
+
lhs = Nokogiri::XML(lhs) if ::String === lhs
|
|
302
|
+
rhs = Nokogiri::XML(rhs) if ::String === rhs
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
# deal with XML Declaration(s)
|
|
307
|
+
|
|
308
|
+
if options[:ignore_xml_declarations]
|
|
309
|
+
|
|
310
|
+
if ::Nokogiri::XML::Document === lhs
|
|
311
|
+
|
|
312
|
+
lhs_root = lhs.root
|
|
313
|
+
lhs = lhs_root if lhs_root
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
if ::Nokogiri::XML::Document === rhs
|
|
317
|
+
|
|
318
|
+
rhs_root = rhs.root
|
|
319
|
+
rhs = rhs_root if rhs_root
|
|
320
|
+
end
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
self.xml_compare_nodes_ lhs, rhs, options
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
def self.xml_compare_nodes_ lhs, rhs, options
|
|
328
|
+
|
|
329
|
+
$stderr.puts "#{self}#{__method__}(lhs (#{lhs.class})=#{self.one_line_ lhs}, rhs (#{rhs.class})=#{self.one_line_ rhs}, options (#{options.class})=#{options})" if $DEBUG
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
# Compare:
|
|
333
|
+
#
|
|
334
|
+
# - name
|
|
335
|
+
# - attributes
|
|
336
|
+
# - content
|
|
337
|
+
# - children
|
|
338
|
+
# -
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
# ##########################
|
|
342
|
+
# name
|
|
343
|
+
|
|
344
|
+
lhs_name = lhs.name
|
|
345
|
+
rhs_name = rhs.name
|
|
346
|
+
|
|
347
|
+
return Result.different :different_node_names, lhs_node: lhs, rhs_node: rhs if lhs_name != rhs_name
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
# ##########################
|
|
351
|
+
# attributes
|
|
352
|
+
|
|
353
|
+
unless options[:ignore_attributes]
|
|
354
|
+
|
|
355
|
+
lhs_attributes = lhs.attribute_nodes
|
|
356
|
+
rhs_attributes = rhs.attribute_nodes
|
|
357
|
+
|
|
358
|
+
return Result.different :different_attribute_count, lhs_node: lhs, rhs_node: rhs if lhs_attributes.count != rhs_attributes.count
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
lhs_attr_list = lhs_attributes.map { |attr| [ attr.name, attr.content ] }
|
|
362
|
+
rhs_attr_list = rhs_attributes.map { |attr| [ attr.name, attr.content ] }
|
|
363
|
+
|
|
364
|
+
if lhs_attr_list != rhs_attr_list
|
|
365
|
+
|
|
366
|
+
# do the sort first
|
|
367
|
+
|
|
368
|
+
lhs_attr_list.sort! { |l, r| l[0] <=> r[0] }
|
|
369
|
+
rhs_attr_list.sort! { |l, r| l[0] <=> r[0] }
|
|
370
|
+
|
|
371
|
+
# Now there are four possibiliies:
|
|
372
|
+
#
|
|
373
|
+
# 1. Different attributes
|
|
374
|
+
# 2. Different attribute order
|
|
375
|
+
# 3. Same (when reordered)
|
|
376
|
+
|
|
377
|
+
if lhs_attr_list == rhs_attr_list
|
|
378
|
+
|
|
379
|
+
if options[:ignore_attribute_order]
|
|
380
|
+
|
|
381
|
+
# 3
|
|
382
|
+
else
|
|
383
|
+
|
|
384
|
+
# 2
|
|
385
|
+
|
|
386
|
+
return Result.different :different_attribute_order, lhs_node: lhs, rhs_node: rhs
|
|
387
|
+
end
|
|
388
|
+
else
|
|
389
|
+
|
|
390
|
+
return Result.different :different_attributes, lhs_node: lhs, rhs_node: rhs
|
|
391
|
+
end
|
|
392
|
+
end
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
# ##########################
|
|
396
|
+
# content
|
|
397
|
+
|
|
398
|
+
unless options[:ignore_content]
|
|
399
|
+
|
|
400
|
+
lhs_texts = self.get_descendants(lhs).select { |el| el.text? }.map { |el| el.content }
|
|
401
|
+
rhs_texts = self.get_descendants(rhs).select { |el| el.text? }.map { |el| el.content }
|
|
402
|
+
|
|
403
|
+
content_same = lhs_texts == rhs_texts
|
|
404
|
+
|
|
405
|
+
unless content_same
|
|
406
|
+
|
|
407
|
+
if options[:normalise_whitespace]
|
|
408
|
+
|
|
409
|
+
lhs_texts = lhs_texts.reject { |s| s.strip.empty? }
|
|
410
|
+
rhs_texts = rhs_texts.reject { |s| s.strip.empty? }
|
|
411
|
+
|
|
412
|
+
content_same = lhs_texts == rhs_texts
|
|
413
|
+
end
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
unless content_same
|
|
417
|
+
|
|
418
|
+
if options[:ignore_content_case]
|
|
419
|
+
|
|
420
|
+
lhs_texts = lhs_texts.reject { |s| s.downcase }
|
|
421
|
+
rhs_texts = rhs_texts.reject { |s| s.downcase }
|
|
422
|
+
|
|
423
|
+
content_same = lhs_texts == rhs_texts
|
|
424
|
+
end
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
unless content_same
|
|
428
|
+
|
|
429
|
+
if options[:ignore_child_node_order]
|
|
430
|
+
|
|
431
|
+
lhs_texts = lhs_texts.sort
|
|
432
|
+
rhs_texts = rhs_texts.sort
|
|
433
|
+
|
|
434
|
+
content_same = lhs_texts == rhs_texts
|
|
435
|
+
end
|
|
436
|
+
end
|
|
437
|
+
|
|
438
|
+
return Result.different :different_node_contents, lhs_node: lhs, rhs_node: rhs unless content_same
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
|
|
442
|
+
# ##########################
|
|
443
|
+
# children (preparation)
|
|
444
|
+
|
|
445
|
+
lhs_children = lhs.children.to_a
|
|
446
|
+
rhs_children = rhs.children.to_a
|
|
447
|
+
|
|
448
|
+
lhs_children.reject! { |child| child.text? && child.content.strip.empty? }
|
|
449
|
+
rhs_children.reject! { |child| child.text? && child.content.strip.empty? }
|
|
450
|
+
|
|
451
|
+
|
|
452
|
+
# ##########################
|
|
453
|
+
# children - count
|
|
454
|
+
|
|
455
|
+
lhs_children_count = lhs_children.count
|
|
456
|
+
rhs_children_count = rhs_children.count
|
|
457
|
+
|
|
458
|
+
return Result.different :different_child_node_count, lhs_node: lhs, rhs_node: rhs if lhs_children_count != rhs_children_count
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
# ##########################
|
|
462
|
+
# children - names
|
|
463
|
+
|
|
464
|
+
lhs_children_names = lhs_children.map { |ch| ch.name }
|
|
465
|
+
rhs_children_names = rhs_children.map { |ch| ch.name }
|
|
466
|
+
|
|
467
|
+
if lhs_children_names != rhs_children_names
|
|
468
|
+
|
|
469
|
+
# At this point, the lists of names of child elements are
|
|
470
|
+
# different. This may be because there are different
|
|
471
|
+
# elements or because they are in a different order. Either
|
|
472
|
+
# way, in order to provide detailed reasons for
|
|
473
|
+
# inequivalency, we must do an order-independent comparison
|
|
474
|
+
|
|
475
|
+
children_sorted_lhs = lhs_children.sort { |x, y| x.name <=> y.name }
|
|
476
|
+
children_sorted_rhs = rhs_children.sort { |x, y| x.name <=> y.name }
|
|
477
|
+
|
|
478
|
+
ch_names_sorted_lhs = children_sorted_lhs.map { |ch| ch.name }
|
|
479
|
+
ch_names_sorted_rhs = children_sorted_rhs.map { |ch| ch.name }
|
|
480
|
+
|
|
481
|
+
ignore_order = options[:ignore_child_node_order]
|
|
482
|
+
|
|
483
|
+
if ignore_order
|
|
484
|
+
|
|
485
|
+
return Result.different :different_child_nodes, lhs_node: lhs, rhs_node: rhs if ch_names_sorted_lhs != ch_names_sorted_rhs
|
|
486
|
+
|
|
487
|
+
# Since they are the same (when reordered), we need to
|
|
488
|
+
# adopt the ordered sequences so that the comparison of
|
|
489
|
+
# the children are meaningful
|
|
490
|
+
|
|
491
|
+
lhs_children = children_sorted_lhs
|
|
492
|
+
rhs_children = children_sorted_rhs
|
|
493
|
+
else
|
|
494
|
+
|
|
495
|
+
# failed, so need to determine whether it's due to
|
|
496
|
+
# different nodes or different order
|
|
497
|
+
|
|
498
|
+
if ch_names_sorted_lhs == ch_names_sorted_rhs
|
|
499
|
+
|
|
500
|
+
return Result.different :different_child_node_order, lhs_node: lhs, rhs_node: rhs
|
|
501
|
+
else
|
|
502
|
+
|
|
503
|
+
return Result.different :different_child_nodes, lhs_node: lhs, rhs_node: rhs
|
|
504
|
+
end
|
|
505
|
+
end
|
|
506
|
+
end
|
|
507
|
+
|
|
508
|
+
(0 ... lhs_children.count).each do |index|
|
|
509
|
+
|
|
510
|
+
ch_lhs = lhs_children[index]
|
|
511
|
+
ch_rhs = rhs_children[index]
|
|
512
|
+
|
|
513
|
+
r = self.xml_compare_nodes_ ch_lhs, ch_rhs, options
|
|
514
|
+
|
|
515
|
+
return r unless r.status
|
|
516
|
+
end
|
|
517
|
+
|
|
518
|
+
return Result.same
|
|
519
|
+
end
|
|
520
|
+
end
|
|
521
|
+
|
|
522
|
+
def self.xml_compare lhs, rhs, **options
|
|
523
|
+
|
|
524
|
+
$stderr.puts "#{self}#{__method__}(lhs (#{lhs.class})=#{Internal_Compare_.one_line_ lhs}, rhs (#{rhs.class})=#{Internal_Compare_.one_line_ rhs}, options (#{options.class})=#{options})" if $DEBUG
|
|
525
|
+
|
|
526
|
+
Internal_Compare_.xml_compare_ lhs, rhs, options
|
|
527
|
+
end
|
|
528
|
+
|
|
529
|
+
def xml_compare lhs, rhs, **options
|
|
530
|
+
|
|
531
|
+
$stderr.puts "#{self}#{__method__}(lhs (#{lhs.class})=#{Internal_Compare_.one_line_ lhs}, rhs (#{rhs.class})=#{Internal_Compare_.one_line_ rhs}, options (#{options.class})=#{options})" if $DEBUG
|
|
532
|
+
|
|
533
|
+
Internal_Compare_.xml_compare_ lhs, rhs, options
|
|
534
|
+
end
|
|
535
|
+
|
|
536
|
+
end # module Compare
|
|
537
|
+
|
|
538
|
+
end # module Utilities
|
|
539
|
+
end # module XML
|
|
540
|
+
end # module Xqsr3
|
|
541
|
+
|
|
542
|
+
# ############################## end of file ############################# #
|
|
543
|
+
|
|
544
|
+
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
|
|
2
|
+
# ######################################################################## #
|
|
3
|
+
# File: lib/xqsr3/xml/_utilities/navigation.rb
|
|
4
|
+
#
|
|
5
|
+
# Purpose: Definition of the ::Xqsr3::XML::Utilities::Navigation
|
|
6
|
+
# module
|
|
7
|
+
#
|
|
8
|
+
# Created: 7th August 2018
|
|
9
|
+
# Updated: 7th August 2018
|
|
10
|
+
#
|
|
11
|
+
# Home: http://github.com/synesissoftware/xqsr3
|
|
12
|
+
#
|
|
13
|
+
# Author: Matthew Wilson
|
|
14
|
+
#
|
|
15
|
+
# Copyright (c) 2018, Matthew Wilson and Synesis Software
|
|
16
|
+
# All rights reserved.
|
|
17
|
+
#
|
|
18
|
+
# Redistribution and use in source and binary forms, with or without
|
|
19
|
+
# modification, are permitted provided that the following conditions are
|
|
20
|
+
# met:
|
|
21
|
+
#
|
|
22
|
+
# * Redistributions of source code must retain the above copyright notice,
|
|
23
|
+
# this list of conditions and the following disclaimer.
|
|
24
|
+
#
|
|
25
|
+
# * Redistributions in binary form must reproduce the above copyright
|
|
26
|
+
# notice, this list of conditions and the following disclaimer in the
|
|
27
|
+
# documentation and/or other materials provided with the distribution.
|
|
28
|
+
#
|
|
29
|
+
# * Neither the names of the copyright holder nor the names of its
|
|
30
|
+
# contributors may be used to endorse or promote products derived from
|
|
31
|
+
# this software without specific prior written permission.
|
|
32
|
+
#
|
|
33
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
|
34
|
+
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
|
35
|
+
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
36
|
+
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
|
37
|
+
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
38
|
+
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
39
|
+
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
40
|
+
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
41
|
+
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
42
|
+
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
43
|
+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
44
|
+
#
|
|
45
|
+
# ######################################################################## #
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
# ##########################################################
|
|
49
|
+
# ::Xqsr3::XML::Utilities::Navigation
|
|
50
|
+
|
|
51
|
+
=begin
|
|
52
|
+
=end
|
|
53
|
+
|
|
54
|
+
require 'xqsr3/quality/parameter_checking'
|
|
55
|
+
|
|
56
|
+
require 'nokogiri'
|
|
57
|
+
|
|
58
|
+
module Xqsr3
|
|
59
|
+
module XML
|
|
60
|
+
module Utilities
|
|
61
|
+
|
|
62
|
+
module Navigation
|
|
63
|
+
|
|
64
|
+
module Internal_Compare_
|
|
65
|
+
|
|
66
|
+
extend ::Xqsr3::Quality::ParameterChecking
|
|
67
|
+
|
|
68
|
+
def self.get_descendants node
|
|
69
|
+
|
|
70
|
+
descendants = []
|
|
71
|
+
|
|
72
|
+
node.children.each do |child|
|
|
73
|
+
|
|
74
|
+
descendants << child
|
|
75
|
+
|
|
76
|
+
descendants += self.get_descendants child
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
descendants
|
|
80
|
+
end
|
|
81
|
+
end # module Internal_Compare_
|
|
82
|
+
|
|
83
|
+
def self.included receiver
|
|
84
|
+
|
|
85
|
+
def receiver.get_descendants node
|
|
86
|
+
|
|
87
|
+
Internal_Compare_.get_descendants node
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def self.get_descendants node
|
|
92
|
+
|
|
93
|
+
Internal_Compare_.get_descendants node
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def get_descendants
|
|
97
|
+
|
|
98
|
+
Internal_Compare_.get_descendants self
|
|
99
|
+
end
|
|
100
|
+
end # module Navigation
|
|
101
|
+
|
|
102
|
+
end # module Utilities
|
|
103
|
+
end # module XML
|
|
104
|
+
end # module Xqsr3
|
|
105
|
+
|
|
106
|
+
# ############################## end of file ############################# #
|
|
107
|
+
|
|
108
|
+
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
|
|
2
|
+
# ######################################################################## #
|
|
3
|
+
# File: lib/xqsr3/xml/version.rb
|
|
4
|
+
#
|
|
5
|
+
# Purpose: Version for xqsr3-xml library
|
|
6
|
+
#
|
|
7
|
+
# Created: 1st March 2019
|
|
8
|
+
# Updated: 2nd March 2019
|
|
9
|
+
#
|
|
10
|
+
# Home: http://github.com/synesissoftware/xqsr3
|
|
11
|
+
#
|
|
12
|
+
# Author: Matthew Wilson
|
|
13
|
+
#
|
|
14
|
+
# Copyright (c) 2019, Matthew Wilson and Synesis Software
|
|
15
|
+
# All rights reserved.
|
|
16
|
+
#
|
|
17
|
+
# Redistribution and use in source and binary forms, with or without
|
|
18
|
+
# modification, are permitted provided that the following conditions are
|
|
19
|
+
# met:
|
|
20
|
+
#
|
|
21
|
+
# * Redistributions of source code must retain the above copyright
|
|
22
|
+
# notice, this list of conditions and the following disclaimer.
|
|
23
|
+
#
|
|
24
|
+
# * Redistributions in binary form must reproduce the above copyright
|
|
25
|
+
# notice, this list of conditions and the following disclaimer in the
|
|
26
|
+
# documentation and/or other materials provided with the distribution.
|
|
27
|
+
#
|
|
28
|
+
# * Neither the names of the copyright holder nor the names of its
|
|
29
|
+
# contributors may be used to endorse or promote products derived from
|
|
30
|
+
# this software without specific prior written permission.
|
|
31
|
+
#
|
|
32
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
|
33
|
+
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
|
34
|
+
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
35
|
+
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
|
36
|
+
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
37
|
+
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
38
|
+
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
39
|
+
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
40
|
+
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
41
|
+
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
42
|
+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
43
|
+
#
|
|
44
|
+
# ######################################################################## #
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
=begin
|
|
48
|
+
=end
|
|
49
|
+
|
|
50
|
+
module Xqsr3
|
|
51
|
+
module XML
|
|
52
|
+
|
|
53
|
+
# Current version of the Xqsr3 library
|
|
54
|
+
VERSION = '0.1.0.1'
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
VERSION_PARTS_ = VERSION.split(/[.]/).collect { |n| n.to_i } # :nodoc:
|
|
58
|
+
public
|
|
59
|
+
# Major version of the Xqsr3 library
|
|
60
|
+
VERSION_MAJOR = VERSION_PARTS_[0] # :nodoc:
|
|
61
|
+
# Minor version of the Xqsr3 library
|
|
62
|
+
VERSION_MINOR = VERSION_PARTS_[1] # :nodoc:
|
|
63
|
+
# Revision version of the Xqsr3 library
|
|
64
|
+
VERSION_REVISION = VERSION_PARTS_[2] # :nodoc:
|
|
65
|
+
|
|
66
|
+
end # module XML
|
|
67
|
+
end # module Xqsr3
|
|
68
|
+
|
|
69
|
+
# ############################## end of file ############################# #
|
|
70
|
+
|
|
71
|
+
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#! /usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
$:.unshift File.join(File.dirname(__FILE__), '../../lib')
|
|
4
|
+
|
|
5
|
+
require 'xqsr3/xml/version'
|
|
6
|
+
|
|
7
|
+
require 'test/unit'
|
|
8
|
+
|
|
9
|
+
class Test_version < Test::Unit::TestCase
|
|
10
|
+
|
|
11
|
+
def test_has_VERSION
|
|
12
|
+
|
|
13
|
+
assert defined? Xqsr3::XML::VERSION
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def test_has_VERSION_MAJOR
|
|
17
|
+
|
|
18
|
+
assert defined? Xqsr3::XML::VERSION_MAJOR
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def test_has_VERSION_MINOR
|
|
22
|
+
|
|
23
|
+
assert defined? Xqsr3::XML::VERSION_MINOR
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def test_has_VERSION_REVISION
|
|
27
|
+
|
|
28
|
+
assert defined? Xqsr3::XML::VERSION_REVISION
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def test_VERSION_has_consistent_format
|
|
32
|
+
|
|
33
|
+
assert_equal Xqsr3::XML::VERSION, "#{Xqsr3::XML::VERSION_MAJOR}.#{Xqsr3::XML::VERSION_MINOR}.#{Xqsr3::XML::VERSION_REVISION}"
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
data/test/unit/ts_all.rb
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#! /usr/bin/env ruby
|
|
2
|
+
#
|
|
3
|
+
# executes all other tests
|
|
4
|
+
|
|
5
|
+
this_dir = File.expand_path(File.dirname(__FILE__))
|
|
6
|
+
|
|
7
|
+
# all tc_*rb in current directory
|
|
8
|
+
Dir[File.join(this_dir, 'tc_*rb')].each { |file| require file }
|
|
9
|
+
|
|
10
|
+
# all ts_*rb in immediate sub-directories
|
|
11
|
+
Dir[File.join(this_dir, '*', 'ts_*rb')].each { |file| require file }
|
|
12
|
+
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#! /usr/bin/env ruby
|
|
2
|
+
#
|
|
3
|
+
# executes all other tests
|
|
4
|
+
|
|
5
|
+
this_dir = File.expand_path(File.dirname(__FILE__))
|
|
6
|
+
|
|
7
|
+
# all tc_*rb in current directory
|
|
8
|
+
Dir[File.join(this_dir, 'tc_*rb')].each { |file| require file }
|
|
9
|
+
|
|
10
|
+
# all ts_*rb in immediate sub-directories
|
|
11
|
+
Dir[File.join(this_dir, '*', 'ts_*rb')].each { |file| require file }
|
|
12
|
+
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
$:.unshift File.join(File.dirname(__FILE__), *(['..'] * 4), 'lib')
|
|
4
|
+
|
|
5
|
+
require 'xqsr3/xml/utilities/compare'
|
|
6
|
+
|
|
7
|
+
require 'xqsr3/extensions/test/unit'
|
|
8
|
+
require 'test/unit'
|
|
9
|
+
|
|
10
|
+
class Test_Xqsr3_XML_Utilities_Compare < Test::Unit::TestCase
|
|
11
|
+
|
|
12
|
+
include ::Xqsr3::XML::Utilities::Compare
|
|
13
|
+
|
|
14
|
+
def test_compare_nil
|
|
15
|
+
|
|
16
|
+
assert xml_compare(nil, nil).same?
|
|
17
|
+
|
|
18
|
+
assert_false xml_compare('', nil).same?
|
|
19
|
+
assert_false xml_compare(nil, '').same?
|
|
20
|
+
|
|
21
|
+
assert xml_compare('', nil, equate_nil_and_empty: true).same?
|
|
22
|
+
assert xml_compare(nil, '', equate_nil_and_empty: true).same?
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def test_compare_empty
|
|
26
|
+
|
|
27
|
+
assert xml_compare('', '').same?
|
|
28
|
+
|
|
29
|
+
assert_false xml_compare('<abc/>', '').same?
|
|
30
|
+
assert_false xml_compare('', '<abc/>').same?
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def test_compare_one_level_1
|
|
34
|
+
|
|
35
|
+
assert xml_compare('<abc/>', '<abc/>').same?
|
|
36
|
+
assert xml_compare('<abc/>', '<abc></abc>').same?
|
|
37
|
+
assert_false xml_compare('<abc/>', '<def/>').same?
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def test_compare_two_level_1
|
|
41
|
+
|
|
42
|
+
assert xml_compare('<parent><child1></child1></parent>', '<parent><child1></child1></parent>').same?
|
|
43
|
+
assert xml_compare('<parent><child1/></parent>', '<parent><child1></child1></parent>').same?
|
|
44
|
+
|
|
45
|
+
r = xml_compare('<parent><child1/></parent>', '<parent><child2/></parent>')
|
|
46
|
+
|
|
47
|
+
assert_false r.same?
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def test_compare_attributes_1
|
|
51
|
+
|
|
52
|
+
lhs = <<END_OF_lhs
|
|
53
|
+
<node name="John Smith" age="21" />
|
|
54
|
+
END_OF_lhs
|
|
55
|
+
|
|
56
|
+
rhs_same = <<END_OF_lhs
|
|
57
|
+
<node age="21" name="John Smith" />
|
|
58
|
+
END_OF_lhs
|
|
59
|
+
|
|
60
|
+
rhs_diff = <<END_OF_lhs
|
|
61
|
+
<node name="John Smith" age="22" />
|
|
62
|
+
END_OF_lhs
|
|
63
|
+
|
|
64
|
+
r = xml_compare lhs, rhs_same, ignore_attribute_order: false
|
|
65
|
+
|
|
66
|
+
assert r.different?, r.details
|
|
67
|
+
assert_equal :different_attribute_order, r.reason
|
|
68
|
+
|
|
69
|
+
r = xml_compare lhs, rhs_same, ignore_attribute_order: true
|
|
70
|
+
|
|
71
|
+
assert r.same?
|
|
72
|
+
|
|
73
|
+
r = xml_compare lhs, rhs_same, element_order: false
|
|
74
|
+
|
|
75
|
+
assert r.same?
|
|
76
|
+
|
|
77
|
+
r = xml_compare lhs, rhs_diff
|
|
78
|
+
|
|
79
|
+
assert r.different?
|
|
80
|
+
assert_equal :different_attributes, r.reason
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def test_compare_two_level_2
|
|
84
|
+
|
|
85
|
+
lhs = <<END_OF_lhs
|
|
86
|
+
<parent>
|
|
87
|
+
<child1/>
|
|
88
|
+
</parent>
|
|
89
|
+
END_OF_lhs
|
|
90
|
+
rhs = <<END_OF_rhs
|
|
91
|
+
<parent>
|
|
92
|
+
<child1>
|
|
93
|
+
</child1>
|
|
94
|
+
</parent>
|
|
95
|
+
END_OF_rhs
|
|
96
|
+
|
|
97
|
+
r = xml_compare lhs, rhs, normalize_whitespace: false
|
|
98
|
+
|
|
99
|
+
assert r.different?, "#{r.details}"
|
|
100
|
+
assert_equal :different_node_contents, r.reason
|
|
101
|
+
|
|
102
|
+
r = xml_compare(lhs, rhs, normalize_whitespace: true)
|
|
103
|
+
|
|
104
|
+
assert r.same?, "#{r.details}"
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def test_compare_two_level_3
|
|
108
|
+
|
|
109
|
+
lhs = <<END_OF_lhs
|
|
110
|
+
<parent>
|
|
111
|
+
<child1/>
|
|
112
|
+
<child2>
|
|
113
|
+
<grandchild2a/>
|
|
114
|
+
</child2>
|
|
115
|
+
</parent>
|
|
116
|
+
END_OF_lhs
|
|
117
|
+
rhs = <<END_OF_rhs
|
|
118
|
+
<parent>
|
|
119
|
+
<child2><grandchild2a/></child2>
|
|
120
|
+
<child1>
|
|
121
|
+
</child1>
|
|
122
|
+
</parent>
|
|
123
|
+
END_OF_rhs
|
|
124
|
+
|
|
125
|
+
r = xml_compare lhs, rhs, normalize_whitespace: true
|
|
126
|
+
|
|
127
|
+
assert r.same?, "#{r.details}"
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def test_different_declarations_and_dont_ignore
|
|
131
|
+
|
|
132
|
+
lhs_str = <<END_OF_lhs_doc
|
|
133
|
+
<?xml version="1.0"?>
|
|
134
|
+
<outer>
|
|
135
|
+
<mid>
|
|
136
|
+
<inner>some text</inner>
|
|
137
|
+
</mid>
|
|
138
|
+
</outer>
|
|
139
|
+
END_OF_lhs_doc
|
|
140
|
+
|
|
141
|
+
rhs_str = <<END_OF_rhs_doc
|
|
142
|
+
<?xml version="1.0"?>
|
|
143
|
+
<mid>
|
|
144
|
+
<inner>some text</inner>
|
|
145
|
+
</mid>
|
|
146
|
+
END_OF_rhs_doc
|
|
147
|
+
|
|
148
|
+
lhs_doc = Nokogiri::XML lhs_str
|
|
149
|
+
rhs_doc = Nokogiri::XML rhs_str
|
|
150
|
+
|
|
151
|
+
expected = rhs_doc
|
|
152
|
+
actual = lhs_doc.at_xpath('/outer/mid')
|
|
153
|
+
|
|
154
|
+
r = xml_compare expected, actual, normalise_whitespace: true, ignore_xml_declarations: false
|
|
155
|
+
|
|
156
|
+
assert !r.same?
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def test_different_declarations_and_do_ignore
|
|
160
|
+
|
|
161
|
+
lhs_str = <<END_OF_lhs_doc
|
|
162
|
+
<?xml version="1.0"?>
|
|
163
|
+
<outer>
|
|
164
|
+
<mid>
|
|
165
|
+
<inner>some text</inner>
|
|
166
|
+
</mid>
|
|
167
|
+
</outer>
|
|
168
|
+
END_OF_lhs_doc
|
|
169
|
+
|
|
170
|
+
rhs_str = <<END_OF_rhs_doc
|
|
171
|
+
<?xml version="1.0"?>
|
|
172
|
+
<mid>
|
|
173
|
+
<inner>some text</inner>
|
|
174
|
+
</mid>
|
|
175
|
+
END_OF_rhs_doc
|
|
176
|
+
|
|
177
|
+
lhs_doc = Nokogiri::XML lhs_str
|
|
178
|
+
rhs_doc = Nokogiri::XML rhs_str
|
|
179
|
+
|
|
180
|
+
expected = rhs_doc
|
|
181
|
+
actual = lhs_doc.at_xpath('/outer/mid')
|
|
182
|
+
|
|
183
|
+
r = xml_compare expected, actual, normalise_whitespace: true, ignore_xml_declarations: true
|
|
184
|
+
|
|
185
|
+
assert r.same?, "#{r.details}"
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def test_different_node_contents_by_child_node_order
|
|
189
|
+
|
|
190
|
+
lhs_str = <<END_OF_lhs_doc
|
|
191
|
+
<?xml version="1.0"?>
|
|
192
|
+
<outer>
|
|
193
|
+
<mid_1>
|
|
194
|
+
<inner>some text</inner>
|
|
195
|
+
</mid_1>
|
|
196
|
+
<mid_2>
|
|
197
|
+
<inner>some more text</inner>
|
|
198
|
+
</mid_2>
|
|
199
|
+
</outer>
|
|
200
|
+
END_OF_lhs_doc
|
|
201
|
+
|
|
202
|
+
rhs_str = <<END_OF_rhs_doc
|
|
203
|
+
<?xml version="1.0"?>
|
|
204
|
+
<outer>
|
|
205
|
+
<mid_2>
|
|
206
|
+
<inner>some more text</inner>
|
|
207
|
+
</mid_2>
|
|
208
|
+
<mid_1>
|
|
209
|
+
<inner>some text</inner>
|
|
210
|
+
</mid_1>
|
|
211
|
+
</outer>
|
|
212
|
+
END_OF_rhs_doc
|
|
213
|
+
|
|
214
|
+
lhs_doc = Nokogiri::XML lhs_str
|
|
215
|
+
rhs_doc = Nokogiri::XML rhs_str
|
|
216
|
+
|
|
217
|
+
expected = rhs_doc
|
|
218
|
+
actual = lhs_doc
|
|
219
|
+
|
|
220
|
+
r = xml_compare expected, actual, ignore_child_node_order: true, normalise_whitespace: true, ignore_xml_declarations: true
|
|
221
|
+
|
|
222
|
+
assert r.same?, "#{r.details}"
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
def test_different_node_contents_by_child_node_order_and_whitespace
|
|
226
|
+
|
|
227
|
+
lhs_str = <<END_OF_lhs_doc
|
|
228
|
+
<?xml version="1.0"?>
|
|
229
|
+
<outer><mid_1><inner>some text</inner></mid_1><mid_2><inner>some more text</inner></mid_2></outer>
|
|
230
|
+
END_OF_lhs_doc
|
|
231
|
+
|
|
232
|
+
rhs_str = <<END_OF_rhs_doc
|
|
233
|
+
<?xml version="1.0"?>
|
|
234
|
+
<outer>
|
|
235
|
+
<mid_2>
|
|
236
|
+
<inner>some more text</inner>
|
|
237
|
+
</mid_2>
|
|
238
|
+
<mid_1>
|
|
239
|
+
<inner>some text</inner>
|
|
240
|
+
</mid_1>
|
|
241
|
+
</outer>
|
|
242
|
+
END_OF_rhs_doc
|
|
243
|
+
|
|
244
|
+
lhs_doc = Nokogiri::XML lhs_str
|
|
245
|
+
rhs_doc = Nokogiri::XML rhs_str
|
|
246
|
+
|
|
247
|
+
expected = rhs_doc
|
|
248
|
+
actual = lhs_doc
|
|
249
|
+
|
|
250
|
+
r = xml_compare expected, actual, ignore_child_node_order: true, normalise_whitespace: true, ignore_xml_declarations: true
|
|
251
|
+
|
|
252
|
+
assert r.same?, "#{r.details}"
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
$:.unshift File.join(File.dirname(__FILE__), *(['..'] * 4), 'lib')
|
|
4
|
+
|
|
5
|
+
require 'xqsr3/xml/utilities/navigation'
|
|
6
|
+
|
|
7
|
+
require 'xqsr3/extensions/test/unit'
|
|
8
|
+
require 'test/unit'
|
|
9
|
+
|
|
10
|
+
require 'nokogiri'
|
|
11
|
+
|
|
12
|
+
class Test_Xqsr3_XML_Utilities_Navigation < Test::Unit::TestCase
|
|
13
|
+
|
|
14
|
+
include ::Xqsr3::XML::Utilities::Navigation
|
|
15
|
+
|
|
16
|
+
def test_get_descendants_1
|
|
17
|
+
|
|
18
|
+
xml_s = <<END_OF_rhs_doc
|
|
19
|
+
<?xml version="1.0"?>
|
|
20
|
+
<document>
|
|
21
|
+
<outer>
|
|
22
|
+
<mid_2>
|
|
23
|
+
<inner>some more text</inner>
|
|
24
|
+
</mid_2>
|
|
25
|
+
<mid_1>
|
|
26
|
+
<inner>some text</inner>
|
|
27
|
+
</mid_1>
|
|
28
|
+
</outer>
|
|
29
|
+
</document>
|
|
30
|
+
END_OF_rhs_doc
|
|
31
|
+
|
|
32
|
+
xml = ::Nokogiri.XML(xml_s)
|
|
33
|
+
doc = xml.children.first
|
|
34
|
+
|
|
35
|
+
descs = self.class.get_descendants xml.children.first
|
|
36
|
+
|
|
37
|
+
assert_not_nil descs
|
|
38
|
+
assert_kind_of ::Array, descs
|
|
39
|
+
|
|
40
|
+
assert_operator 7, :<=, descs.size
|
|
41
|
+
%w{ outer mid_1 mid_2 }.each do |name|
|
|
42
|
+
|
|
43
|
+
assert(descs.find { |el| name == el.name }, "did not find an element named '#{name}' in the collection #{descs}")
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
texts = descs.select { |el| el.text? }
|
|
47
|
+
|
|
48
|
+
[ 'some text', 'some more text' ].each do |text|
|
|
49
|
+
|
|
50
|
+
assert(texts.find { |el| text == el.text }, "did not find an element with the text '#{text}' in the collection #{texts}")
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#! /usr/bin/env ruby
|
|
2
|
+
#
|
|
3
|
+
# executes all other tests
|
|
4
|
+
|
|
5
|
+
this_dir = File.expand_path(File.dirname(__FILE__))
|
|
6
|
+
|
|
7
|
+
# all tc_*rb in current directory
|
|
8
|
+
Dir[File.join(this_dir, 'tc_*rb')].each { |file| require file }
|
|
9
|
+
|
|
10
|
+
# all ts_*rb in immediate sub-directories
|
|
11
|
+
Dir[File.join(this_dir, '*', 'ts_*rb')].each { |file| require file }
|
|
12
|
+
|
metadata
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: xqsr3-xml
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Matt Wilson
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2019-03-02 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: xqsr3
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - '>='
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: 0.31.0
|
|
20
|
+
- - <
|
|
21
|
+
- !ruby/object:Gem::Version
|
|
22
|
+
version: '1.0'
|
|
23
|
+
type: :runtime
|
|
24
|
+
prerelease: false
|
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
26
|
+
requirements:
|
|
27
|
+
- - '>='
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: 0.31.0
|
|
30
|
+
- - <
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '1.0'
|
|
33
|
+
- !ruby/object:Gem::Dependency
|
|
34
|
+
name: nokogiri
|
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - ~>
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '1.6'
|
|
40
|
+
type: :runtime
|
|
41
|
+
prerelease: false
|
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - ~>
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '1.6'
|
|
47
|
+
description: |
|
|
48
|
+
xqsr3 - eXtensions by fine Quantum for Standard Ruby and 3rd-party libraries
|
|
49
|
+
- is a lightweight, low-coupling library of assorted extensions to standard
|
|
50
|
+
ruby and 3rd-party libraries.
|
|
51
|
+
|
|
52
|
+
xqsr3-xml contains the XML-related components for xqsr3, so that the core
|
|
53
|
+
library remains independent of any non-standard libraries.
|
|
54
|
+
email: matthew@synesis.com.au
|
|
55
|
+
executables: []
|
|
56
|
+
extensions: []
|
|
57
|
+
extra_rdoc_files: []
|
|
58
|
+
files:
|
|
59
|
+
- lib/xqsr3/xml/utilities/compare.rb
|
|
60
|
+
- lib/xqsr3/xml/utilities/navigation.rb
|
|
61
|
+
- lib/xqsr3/xml/version.rb
|
|
62
|
+
- test/unit/tc_version.rb
|
|
63
|
+
- test/unit/ts_all.rb
|
|
64
|
+
- test/unit/xml/ts_all.rb
|
|
65
|
+
- test/unit/xml/utilities/tc_compare.rb
|
|
66
|
+
- test/unit/xml/utilities/tc_navigation.rb
|
|
67
|
+
- test/unit/xml/utilities/ts_all.rb
|
|
68
|
+
- README.md
|
|
69
|
+
- LICENSE
|
|
70
|
+
homepage: http://github.com/synesissoftware/xqsr3-xml
|
|
71
|
+
licenses:
|
|
72
|
+
- BSD-3-Clause
|
|
73
|
+
metadata: {}
|
|
74
|
+
post_install_message:
|
|
75
|
+
rdoc_options: []
|
|
76
|
+
require_paths:
|
|
77
|
+
- lib
|
|
78
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - ~>
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '2.0'
|
|
83
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
84
|
+
requirements:
|
|
85
|
+
- - '>='
|
|
86
|
+
- !ruby/object:Gem::Version
|
|
87
|
+
version: '0'
|
|
88
|
+
requirements: []
|
|
89
|
+
rubyforge_project:
|
|
90
|
+
rubygems_version: 2.0.14.1
|
|
91
|
+
signing_key:
|
|
92
|
+
specification_version: 4
|
|
93
|
+
summary: xqsr3-xml
|
|
94
|
+
test_files: []
|