xmatch 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,6 @@
1
1
  require 'erb'
2
2
  require 'fileutils'
3
+ require 'ostruct'
3
4
 
4
5
  module Matcher
5
6
 
@@ -9,20 +10,33 @@ module Matcher
9
10
 
10
11
  def initialize(matcher, args = {})
11
12
  @matcher = matcher
12
- @report_dir = args[:report_dir] || File.dirname(__FILE__) + '/../../reports'
13
+ @report_dir = args[:report_dir] || '/tmp/xmatch'
13
14
  end
14
15
 
15
16
  def format
17
+ match_data = []
18
+ @matcher.lhs.traverse do |elem|
19
+ next if elem.xml?
20
+ match_data << match_info_for(elem)
21
+ elem.attributes.values.each { | attr | match_data << match_info_for(attr) }
22
+ end
23
+
16
24
  FileUtils.mkdir_p(@report_dir)
17
- File.open(File.join(@report_dir, "xmatch.html"), 'w') { |f| f.write(generate_html) }
25
+ File.open(File.join(@report_dir, "xmatch.html"), 'w') { |f| f.write(generate_html(match_data)) }
18
26
  end
19
27
 
20
28
  private
29
+
30
+ def match_info_for(elem)
31
+ result = @matcher.result_for(elem.path)
32
+ OpenStruct.new(:result => result, :line => elem.line, :path => elem.path, :message => @matcher.mismatches[elem.path])
33
+ end
21
34
 
22
- def generate_html
35
+ def generate_html(data)
23
36
  actual_filename = create_actual_file
24
37
  expected_filename = create_expected_file
25
38
  xml = @matcher
39
+ match_info = data
26
40
  html = ERB.new(File.read(TEMPLATE))
27
41
  html.result(binding)
28
42
  end
@@ -4,71 +4,80 @@ module Nokogiri
4
4
 
5
5
  module XML
6
6
 
7
+ class Node
8
+
9
+ def matching(other, matcher)
10
+ other_elem = other.at_xpath(path)
11
+ matcher.record(self, false, "not found") unless other_elem
12
+ other_elem
13
+ end
14
+ end
15
+
16
+ class Document
17
+
18
+ def match?(other, matcher)
19
+ matching(other, matcher)
20
+ end
21
+
22
+ end
23
+
7
24
  class Element
8
25
 
9
26
  def match?(other, matcher)
10
27
  @matcher = matcher
11
- children_match?(other) &&
12
- name_matches?(other) &&
13
- attributes_match?(other)
28
+ other_elem = matching(other, matcher)
29
+ return false unless other_elem
30
+ children_match?(other_elem) & attributes_match?(other_elem)
14
31
  end
15
32
 
16
33
  private
17
34
 
18
35
  def children_match?(other)
19
36
  match = children.size == other.children.size
20
- @matcher.record(path, match, "expected #{children.size} children, got #{other.children.size}")
21
- match
22
- end
23
-
24
- def name_matches?(other)
25
- match = name == other.name
26
- @matcher.record(path, match, "expected element '#{name}', got '#{other.name}'")
37
+ @matcher.record(self, match, "expected #{children.size} children, got #{other.children.size}")
27
38
  match
28
39
  end
29
40
 
30
41
  def attributes_match?(other)
31
42
  match = attributes.size == other.attributes.size
32
- if match
33
- attributes.each_pair do |name, lhs|
34
- match = match && lhs.match?(other.attributes[name], @matcher)
35
- end
36
- else
37
- @matcher.record(path, match, "expected #{attributes.size} attributes, got #{other.attributes.size}")
43
+ unless match
44
+ @matcher.record(self, match, "expected #{attributes.size} attributes, got #{other.attributes.size}")
45
+ return false
38
46
  end
47
+
48
+ attributes.values.each { |attr| match = match & attr.match?(other, @matcher) }
39
49
  match
40
50
  end
41
51
 
42
52
  end
43
53
 
44
- class Document
45
- def match?(other, matcher = nil)
46
- true
47
- end
48
- end
49
-
50
54
  class Text
55
+
51
56
  def match?(other, matcher)
57
+ @matcher = matcher
58
+ other_elem = matching(other, matcher)
59
+ return false unless other_elem
60
+
52
61
  custom_matcher = matcher.custom_matchers[path]
53
- match = custom_matcher ? custom_matcher.call(other) : (content == other.content)
54
- matcher.record(path, match, "expected '#{content}', got '#{other.content}'")
62
+ match = custom_matcher ? custom_matcher.call(other_elem) : (content == other_elem.content)
63
+ @matcher.record(self, match, "expected '#{content}', got '#{other_elem.content}'")
55
64
  match
56
65
  end
66
+
57
67
  end
58
68
 
59
69
  class Attr
70
+
60
71
  def match?(other, matcher)
61
- if other.nil?
62
- # record parent's path: nokogiri's traverse won't find attrs as children, so formatter won't report on them
63
- matcher.record(parent.path, false, "expected attribute missing")
64
- return false
65
- end
72
+ other_elem = matching(other, matcher)
73
+ return false unless other_elem
66
74
 
67
75
  custom_matcher = matcher.custom_matchers[path]
68
- match = custom_matcher ? custom_matcher.call(other) : (value == other.value)
69
- matcher.record(parent.path, match, "attribute '#{name}' expected '#{value}', got '#{other.value}'")
76
+ match = custom_matcher ? custom_matcher.call(other_elem) : (value == other_elem.value)
77
+ matcher.record(self, match, "expected '#{value}', got '#{other_elem.value}'")
70
78
  match
71
79
  end
80
+
72
81
  end
73
82
 
74
83
  end
@@ -1,3 +1,3 @@
1
1
  module Representative
2
- VERSION = "0.1.1".freeze
2
+ VERSION = "0.1.2".freeze
3
3
  end
@@ -35,13 +35,12 @@
35
35
  <th>Path</th>
36
36
  <th>Mismatch</th>
37
37
  </tr>
38
- <% xml.lhs.traverse do | elem | %>
39
- <% next if elem.xml? %>
40
- <tr class=<%= xml.result_for(elem.path) %> >
41
- <td><%= elem.line %></td>
42
- <td><%= elem.path %></td>
43
- <td><%= xml.mismatches[elem.path] || '&nbsp;' %></td>
44
- </tr>
38
+ <% match_info.each do | match | %>
39
+ <tr class=<%= match.result %> >
40
+ <td><%= match.line %></td>
41
+ <td><%= match.path %></td>
42
+ <td><%= match.message || '&nbsp;' %></td>
43
+ </tr>
45
44
  <% end %>
46
45
  </table>
47
46
 
@@ -19,8 +19,8 @@ module Matcher
19
19
  compare(@lhs, @rhs)
20
20
  end
21
21
 
22
- def record(path, result, message = nil)
23
- @results[path] = OpenStruct.new(:result => result, :message => message)
22
+ def record(lhs, result, message)
23
+ @results[lhs.path] = OpenStruct.new(:result => result, :message => message)
24
24
  end
25
25
 
26
26
  def result_for(path)
@@ -28,20 +28,22 @@ module Matcher
28
28
  return "mismatched" if mismatches[path]
29
29
  "unmatched"
30
30
  end
31
-
31
+
32
32
  def matches
33
- match_info = {}
34
- @results.each_pair { |k, v| match_info[k] = '' if v.result }
35
- match_info
33
+ results_that_are(true)
36
34
  end
37
35
 
38
36
  def mismatches
39
- match_info = {}
40
- @results.each_pair { |k, v| match_info[k] = v.message unless v.result }
41
- match_info
37
+ results_that_are(false)
42
38
  end
43
39
 
44
40
  private
41
+
42
+ def results_that_are(value)
43
+ match_info = {}
44
+ @results.each_pair { |path, info| match_info[path] = info.message if info.result == value}
45
+ match_info
46
+ end
45
47
 
46
48
  def parse(xml)
47
49
  xml_as_string = xml.instance_of?(Nokogiri::XML::Document) ? xml.to_xml : xml
@@ -50,10 +52,8 @@ module Matcher
50
52
 
51
53
  def compare(lhs, rhs)
52
54
  return false unless lhs && rhs
53
- match = lhs.match?(rhs, self)
54
- lhs.children.each_with_index do |child, i|
55
- match = match & compare(child, rhs.children[i])
56
- end
55
+ match = true
56
+ lhs.traverse { |node| match = match & node.match?(rhs, self) }
57
57
  match
58
58
  end
59
59
 
@@ -0,0 +1,11 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ require 'nokogiri'
4
+
5
+ describe Matcher::HtmlFormatter do
6
+
7
+ it "should allow output file to be specified"
8
+
9
+ it "should show percentage complete"
10
+
11
+ end
@@ -4,9 +4,9 @@ require 'nokogiri'
4
4
 
5
5
  describe Matcher::Xml do
6
6
 
7
- def verify_mismatch(path, message)
8
- @xml.match(@rhs).should be_false
9
- @xml.mismatches.should have(1).mismatch
7
+ def verify_mismatch(path, message, count = 1)
8
+ match = @xml.match(@rhs)
9
+ @xml.mismatches.should have(count).mismatch
10
10
  @xml.mismatches[path].should == message
11
11
  end
12
12
 
@@ -95,21 +95,13 @@ describe Matcher::Xml do
95
95
  end
96
96
 
97
97
  it "should not match when rhs has a missing element" do
98
- @lhs = <<-eos
99
- <bookstore>
100
- <book category="COOKING">
101
- <title lang="en">Everyday Italian</title>
102
- </book>
103
- </bookstore>
104
- eos
105
-
106
98
  @rhs = <<-eos
107
99
  <bookstore>
108
100
  <book category="COOKING">
109
101
  </book>
110
102
  </bookstore>
111
103
  eos
112
- verify_mismatch("/bookstore/book/title", "expected 1 children, got 0")
104
+ verify_mismatch("/bookstore/book/title", "not found", 2)
113
105
  end
114
106
 
115
107
  end
@@ -124,7 +116,7 @@ describe Matcher::Xml do
124
116
  </bookx>
125
117
  </bookstore>
126
118
  eos
127
- verify_mismatch("/bookstore/book", "expected element 'book', got 'bookx'")
119
+ verify_mismatch("/bookstore/book", "not found", 3)
128
120
  end
129
121
 
130
122
  end
@@ -139,7 +131,7 @@ describe Matcher::Xml do
139
131
  </book>
140
132
  </bookstore>
141
133
  eos
142
- verify_mismatch("/bookstore/book", "expected attribute missing")
134
+ verify_mismatch("/bookstore/book/@category", "not found")
143
135
  end
144
136
 
145
137
  it "should not match when an attribute value doesn't match" do
@@ -150,7 +142,7 @@ describe Matcher::Xml do
150
142
  </book>
151
143
  </bookstore>
152
144
  eos
153
- verify_mismatch("/bookstore/book", "attribute 'category' expected 'COOKING', got 'COOKINGx'")
145
+ verify_mismatch("/bookstore/book/@category", "expected 'COOKING', got 'COOKINGx'")
154
146
  end
155
147
 
156
148
  it "should not match when rhs has an extra attribute" do
@@ -233,11 +225,10 @@ describe Matcher::Xml do
233
225
  </bookstore>
234
226
  eos
235
227
  @xml.match(rhs)
236
- @xml.mismatches.should have(2).mismatches
228
+ @xml.mismatches.should have(4).mismatches
237
229
  end
238
230
 
239
231
  it "should contain parent's path when an attribute doesn't match" do
240
-
241
232
  lhs = <<-eos
242
233
  <bookstore>
243
234
  <book category="COOKING">
@@ -262,18 +253,16 @@ describe Matcher::Xml do
262
253
  eos
263
254
 
264
255
  @xml = Matcher::Xml.new(lhs)
265
- verify_mismatch("/bookstore/book[2]", "expected attribute missing")
256
+ verify_mismatch("/bookstore/book[2]/@category", "not found")
266
257
  end
267
258
 
268
259
  context 'matches' do
269
260
 
270
- it "should be provided with no message" do
271
- lhs = "<bookstore><book></book></bookstore>"
261
+ it "should contain each match" do
262
+ lhs = "<bookstore><book>foo</book></bookstore>"
272
263
  xml = Matcher::Xml.new(lhs)
273
264
  xml.match(lhs)
274
- xml.matches.should have(2).matches
275
- xml.matches.should include("/bookstore")
276
- xml.matches.values.all? {|m| m == ''}.should be_true
265
+ xml.matches.should have(3).matches
277
266
  end
278
267
 
279
268
  end
@@ -282,26 +271,18 @@ describe Matcher::Xml do
282
271
 
283
272
  context "match results" do
284
273
 
285
- it "provides all results"
286
-
287
274
  it "returns 'matched' for a path that matched correctly" do
288
275
  xml = Matcher::Xml.new("<bookstore></bookstore>")
289
276
  xml.match("<bookstore></bookstore>")
290
277
  xml.result_for("/bookstore").should == "matched"
291
278
  end
292
279
 
293
- it "returns 'mismatched' for a path that was mismatched" do
280
+ it "returns 'unmatched' for a path that was not found" do
294
281
  xml = Matcher::Xml.new("<bookstore></bookstore>")
295
282
  xml.match("<bookstorex></bookstorex>")
296
283
  xml.result_for("/bookstore").should == "mismatched"
297
284
  end
298
285
 
299
- it "returns 'unmatched' for a path that was not matched at all" do
300
- xml = Matcher::Xml.new("<bookstore><foo></foo></bookstore>")
301
- xml.match("<bookstorex></bookstorex>")
302
- xml.result_for("/bookstore/foo").should == "unmatched"
303
- end
304
-
305
286
  end
306
287
 
307
288
  context "custom matchers" do
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: 25
4
+ hash: 31
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 1
9
- - 1
10
- version: 0.1.1
9
+ - 2
10
+ version: 0.1.2
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-18 00:00:00 +11:00
18
+ date: 2010-11-19 00:00:00 +11:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -93,6 +93,7 @@ files:
93
93
  - spec/fixtures/books7.xml
94
94
  - spec/fixtures/books8.xml
95
95
  - spec/fixtures/books9.xml
96
+ - spec/matcher/html_formatter_spec.rb
96
97
  - spec/matcher/smoke_spec.rb
97
98
  - spec/matcher/xml_spec.rb
98
99
  - spec/spec_helper.rb
@@ -142,6 +143,7 @@ test_files:
142
143
  - spec/fixtures/books7.xml
143
144
  - spec/fixtures/books8.xml
144
145
  - spec/fixtures/books9.xml
146
+ - spec/matcher/html_formatter_spec.rb
145
147
  - spec/matcher/smoke_spec.rb
146
148
  - spec/matcher/xml_spec.rb
147
149
  - spec/spec_helper.rb