xmatch 0.1.4 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -27,9 +27,9 @@ A matcher provides access to the match information by xpath values:
27
27
  Custom matchers
28
28
  ---------------
29
29
  The actual values of some xml elements are hard to know in advance (timestamps and ids being typical examples). XMatch allows custom matchers to be applied
30
- to provide a good guess at a match in advance of the match being run. Custom matchers are Ruby Procs that take the element to match as an argument. They are identified by the xpath of the element they should be applied to.
30
+ to provide a good guess at a match in advance of the match being run. Custom matchers are predicates provided as Ruby Procs, identified by the xpath of the element they should be applied to.
31
31
 
32
- custom_matchers = { "/bookstore/@id" => lambda {|elem| elem.value =~ /\d+/} }
32
+ custom_matchers = { "/bookstore/@id" => lambda {|elem| elem.value.match(/\d+/) }
33
33
  xml = Matcher::Xml.new("<bookstore id='1'></bookstore>", custom_matchers)
34
34
  xml.match("<bookstore id='2'></bookstore>") # ==> true
35
35
 
@@ -22,35 +22,38 @@ module Matcher
22
22
  elem.attributes.values.each { | attr | match_data << match_info_for(attr) }
23
23
  end
24
24
  match_data.sort! {|a, b| a.line <=> b.line}
25
-
25
+
26
26
  FileUtils.mkdir_p(@report_dir)
27
- filename = "xmatch.html"
28
- filename = "#{@prefix}-xmatch.html" if @prefix
27
+ filename = @prefix ? "#{@prefix}-xmatch.html" : "xmatch.html"
29
28
  File.open(File.join(@report_dir, filename), 'w') { |f| f.write(generate_html(match_data)) }
30
29
  end
31
30
 
32
31
  private
33
-
32
+
34
33
  def match_info_for(elem)
34
+ info = @matcher.results[elem.path]
35
35
  result = @matcher.result_for(elem.path)
36
- message = result == "unmatched" ? "Unmatched" : @matcher.mismatches[elem.path]
37
- OpenStruct.new(:result => result, :line => elem.line, :path => elem.path, :message => message)
36
+ OpenStruct.new(:result => result,
37
+ :line => elem.line,
38
+ :path => elem.path,
39
+ :expected => info ? info.expected : Matcher::Xml::EXISTENCE,
40
+ :actual => info ? info.actual : Matcher::Xml::UNMATCHED)
38
41
  end
39
-
42
+
40
43
  def generate_html(data)
41
44
  actual_filename = create_actual_file
42
45
  expected_filename = create_expected_file
43
- xml = @matcher
46
+ xml = @matcher
44
47
  completedness = compute_completedness
45
48
  match_info = data
46
49
  html = ERB.new(File.read(TEMPLATE))
47
- html.result(binding)
50
+ html.result(binding)
48
51
  end
49
-
52
+
50
53
  def compute_completedness
51
54
  (@matcher.matches.size.to_f / @matcher.results.size.to_f * 100).to_i
52
55
  end
53
-
56
+
54
57
  def create_expected_file
55
58
  write_xml("expected", @matcher.lhs)
56
59
  end
@@ -61,11 +64,11 @@ module Matcher
61
64
 
62
65
  def write_xml(name, xml)
63
66
  file_name = "#{name}-#{Time.now.to_i}.xml"
64
- file_name = "#{@prefix}-#{file_name}" if @prefix
67
+ file_name = "#{@prefix}-#{file_name}" if @prefix
65
68
  File.open(File.join(@report_dir, file_name), 'w') { |f| f.write(xml)}
66
69
  file_name
67
70
  end
68
-
71
+
69
72
  end
70
73
 
71
74
  end
@@ -8,7 +8,7 @@ module Nokogiri
8
8
 
9
9
  def matching(other, matcher)
10
10
  other_elem = other.at_xpath(path)
11
- matcher.record(self, false, Matcher::Xml::NOT_FOUND) unless other_elem
11
+ matcher.record(self.path, false, Matcher::Xml::EXISTENCE, Matcher::Xml::NOT_FOUND) unless other_elem
12
12
  other_elem
13
13
  end
14
14
  end
@@ -34,14 +34,14 @@ module Nokogiri
34
34
 
35
35
  def children_match?(other)
36
36
  match = children.size == other.children.size
37
- @matcher.record(self, match, "expected #{children.size} children, got #{other.children.size}")
37
+ @matcher.record(self.path, match, "#{children.size} children", "#{other.children.size} children")
38
38
  match
39
39
  end
40
40
 
41
41
  def attributes_match?(other)
42
42
  match = attributes.size == other.attributes.size
43
43
  unless match
44
- @matcher.record(self, match, "expected #{attributes.size} attributes, got #{other.attributes.size}")
44
+ @matcher.record(self.path, match, "#{attributes.size} attributes", "#{other.attributes.size} attributes")
45
45
  return false
46
46
  end
47
47
 
@@ -60,7 +60,7 @@ module Nokogiri
60
60
 
61
61
  custom_matcher = matcher.custom_matchers[path]
62
62
  match = custom_matcher ? custom_matcher.call(other_elem) : (content == other_elem.content)
63
- @matcher.record(self, match, "expected '#{content}', got '#{other_elem.content}'")
63
+ @matcher.record(self.path, match, content, other_elem.content)
64
64
  match
65
65
  end
66
66
 
@@ -74,7 +74,7 @@ module Nokogiri
74
74
 
75
75
  custom_matcher = matcher.custom_matchers[path]
76
76
  match = custom_matcher ? custom_matcher.call(other_elem) : (value == other_elem.value)
77
- matcher.record(self, match, "expected '#{value}', got '#{other_elem.value}'")
77
+ matcher.record(self.path, match, value, other_elem.value)
78
78
  match
79
79
  end
80
80
 
@@ -1,3 +1,3 @@
1
1
  module Representative
2
- VERSION = "0.1.4".freeze
2
+ VERSION = "0.1.5".freeze
3
3
  end
@@ -35,13 +35,15 @@ Expected xml document is <b><%= completedness %>%</b> 'matched'.
35
35
  <tr>
36
36
  <th>Line</th>
37
37
  <th>Path</th>
38
- <th>Mismatch</th>
38
+ <th>Expected</th>
39
+ <th>Actual</th>
39
40
  </tr>
40
41
  <% match_info.each do | match | %>
41
42
  <tr class=<%= match.result %> >
42
43
  <td><%= match.line %></td>
43
44
  <td><%= match.path %></td>
44
- <td><%= match.message || '&nbsp;' %></td>
45
+ <td><%= match.expected %></td>
46
+ <td><%= match.actual %></td>
45
47
  </tr>
46
48
  <% end %>
47
49
  </table>
@@ -5,7 +5,9 @@ module Matcher
5
5
 
6
6
  class Xml
7
7
 
8
- NOT_FOUND = "Not found in compared document"
8
+ NOT_FOUND = "[Not found]"
9
+ EXISTENCE = "[Existence]"
10
+ UNMATCHED = "[Unmatched]"
9
11
 
10
12
  attr_reader :lhs, :rhs, :custom_matchers, :results
11
13
 
@@ -21,8 +23,10 @@ module Matcher
21
23
  compare(@lhs, @rhs)
22
24
  end
23
25
 
24
- def record(lhs, result, message)
25
- @results[lhs.path] = OpenStruct.new(:result => result, :message => message)
26
+ def record(path, result, expected, actual)
27
+ # support 0 as true (for regex matches)
28
+ r = !result || result.nil? ? false : true
29
+ @results[path] = OpenStruct.new(:result => r, :expected => expected, :actual => actual)
26
30
  end
27
31
 
28
32
  def result_for(path)
@@ -43,7 +47,7 @@ module Matcher
43
47
 
44
48
  def results_that_are(value)
45
49
  match_info = {}
46
- @results.each_pair { |path, info| match_info[path] = info.message if info.result == value}
50
+ @results.each { |path, info| match_info[path] = info if info.result == value}
47
51
  match_info
48
52
  end
49
53
 
@@ -4,8 +4,5 @@ require 'nokogiri'
4
4
 
5
5
  describe Matcher::HtmlFormatter do
6
6
 
7
- it "should allow output file to be specified"
8
-
9
- it "should show percentage complete"
10
7
 
11
8
  end
@@ -4,10 +4,12 @@ require 'nokogiri'
4
4
 
5
5
  describe Matcher::Xml do
6
6
 
7
- def verify_mismatch(path, message, count = 1)
7
+ def verify_mismatch(path, expected, actual, count = 1)
8
8
  match = @xml.match(@rhs)
9
9
  @xml.mismatches.should have(count).mismatch
10
- @xml.mismatches[path].should == message
10
+ @xml.mismatches[path].result.should be_false
11
+ @xml.mismatches[path].expected.should == expected.to_s
12
+ @xml.mismatches[path].actual.should == actual
11
13
  end
12
14
 
13
15
  context "attributes" do
@@ -91,7 +93,7 @@ describe Matcher::Xml do
91
93
  <book></book>
92
94
  </bookstore>
93
95
  eos
94
- verify_mismatch("/bookstore", "expected 1 children, got 2")
96
+ verify_mismatch("/bookstore", "1 children", "2 children")
95
97
  end
96
98
 
97
99
  it "should not match when rhs has a missing element" do
@@ -101,7 +103,7 @@ describe Matcher::Xml do
101
103
  </book>
102
104
  </bookstore>
103
105
  eos
104
- verify_mismatch("/bookstore/book/title", Matcher::Xml::NOT_FOUND, 2)
106
+ verify_mismatch("/bookstore/book/title", Matcher::Xml::EXISTENCE, Matcher::Xml::NOT_FOUND, 2)
105
107
  end
106
108
 
107
109
  end
@@ -116,7 +118,7 @@ describe Matcher::Xml do
116
118
  </bookx>
117
119
  </bookstore>
118
120
  eos
119
- verify_mismatch("/bookstore/book", Matcher::Xml::NOT_FOUND, 3)
121
+ verify_mismatch("/bookstore/book", Matcher::Xml::EXISTENCE, Matcher::Xml::NOT_FOUND, 3)
120
122
  end
121
123
 
122
124
  end
@@ -131,7 +133,7 @@ describe Matcher::Xml do
131
133
  </book>
132
134
  </bookstore>
133
135
  eos
134
- verify_mismatch("/bookstore/book/@category", Matcher::Xml::NOT_FOUND)
136
+ verify_mismatch("/bookstore/book/@category", Matcher::Xml::EXISTENCE, Matcher::Xml::NOT_FOUND)
135
137
  end
136
138
 
137
139
  it "should not match when an attribute value doesn't match" do
@@ -142,7 +144,7 @@ describe Matcher::Xml do
142
144
  </book>
143
145
  </bookstore>
144
146
  eos
145
- verify_mismatch("/bookstore/book/@category", "expected 'COOKING', got 'COOKINGx'")
147
+ verify_mismatch("/bookstore/book/@category", 'COOKING', "COOKINGx")
146
148
  end
147
149
 
148
150
  it "should not match when rhs has an extra attribute" do
@@ -153,7 +155,7 @@ describe Matcher::Xml do
153
155
  </book>
154
156
  </bookstore>
155
157
  eos
156
- verify_mismatch("/bookstore/book", "expected 1 attributes, got 2")
158
+ verify_mismatch("/bookstore/book", "1 attributes", "2 attributes")
157
159
  end
158
160
 
159
161
  it "should not match when rhs has less attributes" do
@@ -164,7 +166,7 @@ describe Matcher::Xml do
164
166
  </book>
165
167
  </bookstore>
166
168
  eos
167
- verify_mismatch("/bookstore/book/title", "expected 1 attributes, got 0")
169
+ verify_mismatch("/bookstore/book/title", "1 attributes", "0 attributes")
168
170
  end
169
171
 
170
172
  it "should not match when rhs has more attributes" do
@@ -175,7 +177,7 @@ describe Matcher::Xml do
175
177
  </book>
176
178
  </bookstore>
177
179
  eos
178
- verify_mismatch("/bookstore/book/title", "expected 1 attributes, got 2")
180
+ verify_mismatch("/bookstore/book/title", "1 attributes", "2 attributes")
179
181
  end
180
182
 
181
183
  end
@@ -190,7 +192,7 @@ describe Matcher::Xml do
190
192
  </book>
191
193
  </bookstore>
192
194
  eos
193
- verify_mismatch("/bookstore/book/title/text()", "expected 'Everyday Italian', got 'Everyday Italianx'")
195
+ verify_mismatch("/bookstore/book/title/text()", "Everyday Italian", "Everyday Italianx")
194
196
  end
195
197
 
196
198
  end
@@ -257,7 +259,7 @@ describe Matcher::Xml do
257
259
  eos
258
260
 
259
261
  @xml = Matcher::Xml.new(lhs)
260
- verify_mismatch("/bookstore/book[2]/@category", Matcher::Xml::NOT_FOUND)
262
+ verify_mismatch("/bookstore/book[2]/@category", Matcher::Xml::EXISTENCE, Matcher::Xml::NOT_FOUND)
261
263
  end
262
264
 
263
265
  context 'matches' do
@@ -268,6 +270,15 @@ describe Matcher::Xml do
268
270
  xml.match(lhs)
269
271
  xml.matches.should have(3).matches
270
272
  end
273
+
274
+ it "should have expected and actual results" do
275
+ lhs = "<bookstore><book>foo</book></bookstore>"
276
+ xml = Matcher::Xml.new(lhs)
277
+ xml.match(lhs).should be_true
278
+ match_info = xml.matches["/bookstore"]
279
+ match_info.expected.should == "1 children"
280
+ match_info.actual.should == "1 children"
281
+ end
271
282
 
272
283
  end
273
284
 
@@ -307,6 +318,14 @@ describe Matcher::Xml do
307
318
  xml = Matcher::Xml.new("<bookstore><book>foo</book></bookstore", custom_matchers)
308
319
  xml.match("<bookstore><book>bar</book></bookstore").should be_true
309
320
  end
321
+
322
+ it "supports regex style matching" do
323
+ custom_matchers = { "/bookstore/book/text()" => lambda {|elem| elem.content =~ /bar/} }
324
+ xml = Matcher::Xml.new("<bookstore><book>foo</book></bookstore", custom_matchers)
325
+ xml.match("<bookstore><book>bar</book></bookstore").should be_true
326
+ xml.mismatches.should be_empty
327
+ xml.matches.should have(3).matches
328
+ end
310
329
 
311
330
  end
312
331
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xmatch
3
3
  version: !ruby/object:Gem::Version
4
- hash: 19
4
+ hash: 17
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 1
9
- - 4
10
- version: 0.1.4
9
+ - 5
10
+ version: 0.1.5
11
11
  platform: ruby
12
12
  authors:
13
13
  - Peter Moran
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-11-19 00:00:00 +11:00
18
+ date: 2010-11-23 00:00:00 +11:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency