json-deep-compare 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,202 +1,7 @@
1
- module JsonDeepCompare
2
- VERSION = '0.1.0'
3
-
4
- class DocumentComparison
5
- def initialize(lval, rval, options = {})
6
- if exclusions = options[:exclusions]
7
- options[:exclusions] = [exclusions] unless exclusions.is_a?(Array)
8
- else
9
- options[:exclusions] = []
10
- end
11
- @root_comparisons = []
12
- @root_comparisons << NodeComparison.new(lval, rval, ":root", options)
13
- @root_comparisons << NodeComparison.new(rval, lval, ":root", options)
14
- end
15
-
16
- def difference_messages
17
- ldiffs = @root_comparisons.first.differences
18
- rdiffs = @root_comparisons.last.differences
19
- differences = ldiffs.dup
20
- ldiff_selectors = ldiffs.map { |ldiff| ldiff.selector }
21
- rdiffs.each do |rdiff|
22
- unless ldiff_selectors.include?(rdiff.selector)
23
- differences << rdiff.reverse
24
- end
25
- end
26
- differences = differences.sort_by &:selector
27
- differences.map(&:message).join("\n")
28
- end
29
-
30
- def equal?
31
- @root_comparisons.all?(&:equal?)
32
- end
33
- end
34
-
35
- class NodeComparison
36
- ExcerptPadding = 15
37
- attr_reader :lval, :rval, :selector
38
-
39
- def initialize(lval, rval, selector, options = {})
40
- @lval, @rval, @selector, @options = lval, rval, selector, options
41
- @children = []
42
- if lval.is_a?(Hash)
43
- if rval.is_a?(Hash)
44
- lval.each do |key, left_sub_value|
45
- @children << NodeComparison.new(
46
- left_sub_value,
47
- rval[key],
48
- "#{selector} > .#{key}",
49
- options
50
- )
51
- end
52
- end
53
- elsif lval.is_a?(Array)
54
- if rval.is_a?(Array)
55
- lval.each_with_index do |left_sub_value, i|
56
- @children << NodeComparison.new(
57
- left_sub_value,
58
- rval[i],
59
- "#{selector} :nth-child(#{i+1})",
60
- options
61
- )
62
- end
63
- end
64
- end
65
- end
66
-
67
- def blank?(value)
68
- value.respond_to?(:empty?) ? value.empty? : !value
69
- end
70
-
71
- def blank_equality?
72
- @options[:blank_equality]
73
- end
74
-
75
- def differences
76
- if equal?
77
- []
78
- else
79
- if leaf?
80
- if excerptable_difference?
81
- [excerpted_difference]
82
- else
83
- [Difference.new(
84
- @selector, "expected to be :lval but was :rval",
85
- lval: value_inspect(@lval), rval: value_inspect(@rval)
86
- )]
87
- end
88
- else
89
- @children.map(&:differences).compact.flatten
90
- end
91
- end
92
- end
93
-
94
- def equal?
95
- if leaf?
96
- if selector_excluded?
97
- true
98
- elsif equality_proc
99
- equality_proc.call(@lval, @rval)
100
- else
101
- @lval == @rval || (blank_equality? && blank?(@lval) && blank?(@rval))
102
- end
103
- else
104
- @children.all?(&:equal?)
105
- end
106
- end
107
-
108
- def equality_proc
109
- @options[:equality]
110
- end
1
+ require 'json-deep-compare/assertions'
2
+ require 'json-deep-compare/document_comparison'
3
+ require 'json-deep-compare/node_comparison'
4
+ require 'json-deep-compare/version'
111
5
 
112
- def excerptable_difference?
113
- @lval.is_a?(String) and @rval.is_a?(String) && (
114
- @lval.size > ExcerptPadding * 2 || @rval.size > ExcerptPadding * 2
115
- )
116
- end
117
-
118
- def excerpted_difference
119
- difference_start = (0..@lval.length).detect { |i| @lval[i] != @rval[i] }
120
- range_start = if difference_start > ExcerptPadding
121
- difference_start - ExcerptPadding
122
- else
123
- 0
124
- end
125
- left_excerpt = @lval[range_start..difference_start+ExcerptPadding]
126
- right_excerpt = @rval[range_start..difference_start+ExcerptPadding]
127
- if difference_start - ExcerptPadding > 0
128
- left_excerpt = "..." + left_excerpt
129
- right_excerpt = "..." + right_excerpt
130
- end
131
- if difference_start + ExcerptPadding < @lval.length
132
- left_excerpt = left_excerpt + '...'
133
- end
134
- if difference_start + ExcerptPadding < @rval.length
135
- right_excerpt = right_excerpt + '...'
136
- end
137
- Difference.new(
138
- @selector,
139
- "differs starting at char :difference_start: :lval differs from :rval",
140
- difference_start: difference_start.to_s,
141
- lval: left_excerpt.inspect, rval: right_excerpt.inspect
142
- )
143
- end
144
-
145
- def leaf?
146
- @children.empty?
147
- end
148
-
149
- def selector_excluded?
150
- @options[:exclusions].any? { |exclusion|
151
- if exclusion.is_a?(String)
152
- exclusion == @selector
153
- else
154
- @selector =~ exclusion
155
- end
156
- }
157
- end
158
-
159
- def value_inspect(value)
160
- str = value.inspect
161
- if str.length >= 40
162
- "#{value.class.name} #{str[0..37]}..."
163
- else
164
- str
165
- end
166
- end
167
-
168
- class Difference
169
- attr_reader :selector
170
-
171
- def initialize(selector, msg_template, variables)
172
- @selector, @msg_template, @variables =
173
- selector, msg_template, variables
174
- end
175
-
176
- def message
177
- msg = @msg_template
178
- @variables.each do |name, value|
179
- msg = msg.gsub(/#{name.inspect}/, value)
180
- end
181
- "#{@selector.inspect} #{msg}"
182
- end
183
-
184
- def reverse
185
- reversed_variables = {lval: @variables[:rval], rval: @variables[:lval]}
186
- (@variables.keys - [:lval, :rval]).each do |other_var|
187
- reversed_variables[other_var] = @variables[other_var]
188
- end
189
- Difference.new(@selector, @msg_template, reversed_variables)
190
- end
191
- end
192
- end
193
-
194
- module Assertions
195
- def assert_json_equal(expected, actual, exclusions = nil)
196
- comparison = DocumentComparison.new(expected, actual, exclusions: exclusions)
197
- unless comparison.equal?
198
- fail comparison.difference_messages
199
- end
200
- end
201
- end
6
+ module JsonDeepCompare
202
7
  end
@@ -0,0 +1,10 @@
1
+ module JsonDeepCompare
2
+ module Assertions
3
+ def assert_json_equal(expected, actual, options = {})
4
+ comparison = DocumentComparison.new(expected, actual, options)
5
+ unless comparison.equal?
6
+ fail comparison.difference_messages
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,36 @@
1
+ module JsonDeepCompare
2
+ class DocumentComparison
3
+ def initialize(lval, rval, options = {})
4
+ if exclusions = options[:exclusions]
5
+ options[:exclusions] = [exclusions] unless exclusions.is_a?(Array)
6
+ else
7
+ options[:exclusions] = []
8
+ end
9
+ @root_comparisons = []
10
+ @root_comparisons << NodeComparison.new(
11
+ lval, rval, ":root", options.merge(direction: :left)
12
+ )
13
+ @root_comparisons << NodeComparison.new(
14
+ rval, lval, ":root", options.merge(direction: :right)
15
+ )
16
+ end
17
+
18
+ def difference_messages
19
+ ldiffs = @root_comparisons.first.differences
20
+ rdiffs = @root_comparisons.last.differences
21
+ differences = ldiffs.dup
22
+ ldiff_selectors = ldiffs.map { |ldiff| ldiff.selector }
23
+ rdiffs.each do |rdiff|
24
+ unless ldiff_selectors.include?(rdiff.selector)
25
+ differences << rdiff.reverse
26
+ end
27
+ end
28
+ differences = differences.sort_by &:selector
29
+ differences.map(&:message).join("\n")
30
+ end
31
+
32
+ def equal?
33
+ @root_comparisons.all?(&:equal?)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,194 @@
1
+ module JsonDeepCompare
2
+ class NodeComparison
3
+ ExcerptPadding = 15
4
+ attr_reader :lval, :rval, :selector
5
+
6
+ def initialize(lval, rval, selector, options = {})
7
+ @lval, @rval, @selector, @options = lval, rval, selector, options
8
+ @children = []
9
+ if lval.is_a?(Hash)
10
+ if rval.is_a?(Hash)
11
+ lval.each do |key, left_sub_value|
12
+ @children << NodeComparison.new(
13
+ left_sub_value,
14
+ rval[key],
15
+ "#{selector} > .#{key}",
16
+ options
17
+ )
18
+ end
19
+ end
20
+ elsif lval.is_a?(Array)
21
+ if rval.is_a?(Array)
22
+ lval.each_with_index do |left_sub_value, i|
23
+ @children << NodeComparison.new(
24
+ left_sub_value,
25
+ rval[i],
26
+ "#{selector} :nth-child(#{i+1})",
27
+ options
28
+ )
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ def blank?(value)
35
+ value.respond_to?(:empty?) ? value.empty? : !value
36
+ end
37
+
38
+ def blank_equality?
39
+ @options[:blank_equality]
40
+ end
41
+
42
+ def differences
43
+ if equal?
44
+ []
45
+ else
46
+ if leaf?
47
+ if excerptable_difference?
48
+ [excerpted_difference]
49
+ else
50
+ [Difference.new(
51
+ @selector, "expected to be :lval but was :rval",
52
+ lval: value_inspect(@lval), rval: value_inspect(@rval)
53
+ )]
54
+ end
55
+ else
56
+ @children.map(&:differences).compact.flatten
57
+ end
58
+ end
59
+ end
60
+
61
+ def equal?
62
+ if leaf?
63
+ if selector_excluded?
64
+ true
65
+ elsif equality_proc
66
+ equality_proc.call(lval_for_equality, rval_for_equality)
67
+ elsif blank_equality? && blank?(lval_for_equality) && blank?(rval_for_equality)
68
+ true
69
+ else
70
+ lval_for_equality == rval_for_equality
71
+ end
72
+ else
73
+ @children.all?(&:equal?)
74
+ end
75
+ end
76
+
77
+ def equality_proc
78
+ @options[:equality]
79
+ end
80
+
81
+ def excerptable_difference?
82
+ @lval.is_a?(String) and @rval.is_a?(String) && (
83
+ @lval.size > ExcerptPadding * 2 || @rval.size > ExcerptPadding * 2
84
+ )
85
+ end
86
+
87
+ def excerpted_difference
88
+ difference_start = (0..@lval.length).detect { |i| @lval[i] != @rval[i] }
89
+ range_start = if difference_start > ExcerptPadding
90
+ difference_start - ExcerptPadding
91
+ else
92
+ 0
93
+ end
94
+ left_excerpt = @lval[range_start..difference_start+ExcerptPadding]
95
+ right_excerpt = @rval[range_start..difference_start+ExcerptPadding]
96
+ if difference_start - ExcerptPadding > 0
97
+ left_excerpt = "..." + left_excerpt
98
+ right_excerpt = "..." + right_excerpt
99
+ end
100
+ if difference_start + ExcerptPadding < @lval.length
101
+ left_excerpt = left_excerpt + '...'
102
+ end
103
+ if difference_start + ExcerptPadding < @rval.length
104
+ right_excerpt = right_excerpt + '...'
105
+ end
106
+ Difference.new(
107
+ @selector,
108
+ "differs starting at char :difference_start: :lval differs from :rval",
109
+ difference_start: difference_start.to_s,
110
+ lval: left_excerpt.inspect, rval: right_excerpt.inspect
111
+ )
112
+ end
113
+
114
+ def leaf?
115
+ @children.empty?
116
+ end
117
+
118
+ def left_to_right?
119
+ @options[:direction] == :left
120
+ end
121
+
122
+ def lval_for_equality
123
+ @_lval_for_equality ||= begin
124
+ if left_to_right? && substitution
125
+ substitution
126
+ else
127
+ lval
128
+ end
129
+ end
130
+ end
131
+
132
+ def right_to_left?
133
+ @options[:direction] == :right
134
+ end
135
+
136
+ def rval_for_equality
137
+ @_rval_for_equality ||= begin
138
+ if right_to_left? && substitution
139
+ substitution
140
+ else
141
+ rval
142
+ end
143
+ end
144
+ end
145
+
146
+ def selector_excluded?
147
+ @options[:exclusions].any? { |exclusion|
148
+ if exclusion.is_a?(String)
149
+ exclusion == @selector
150
+ else
151
+ @selector =~ exclusion
152
+ end
153
+ }
154
+ end
155
+
156
+ def substitution
157
+ @options[:substitutions] && @options[:substitutions][selector]
158
+ end
159
+
160
+ def value_inspect(value)
161
+ str = value.inspect
162
+ if str.length >= 40
163
+ "#{value.class.name} #{str[0..37]}..."
164
+ else
165
+ str
166
+ end
167
+ end
168
+
169
+ class Difference
170
+ attr_reader :selector
171
+
172
+ def initialize(selector, msg_template, variables)
173
+ @selector, @msg_template, @variables =
174
+ selector, msg_template, variables
175
+ end
176
+
177
+ def message
178
+ msg = @msg_template
179
+ @variables.each do |name, value|
180
+ msg = msg.gsub(/#{name.inspect}/, value)
181
+ end
182
+ "#{@selector.inspect} #{msg}"
183
+ end
184
+
185
+ def reverse
186
+ reversed_variables = {lval: @variables[:rval], rval: @variables[:lval]}
187
+ (@variables.keys - [:lval, :rval]).each do |other_var|
188
+ reversed_variables[other_var] = @variables[other_var]
189
+ end
190
+ Difference.new(@selector, @msg_template, reversed_variables)
191
+ end
192
+ end
193
+ end
194
+ end
@@ -0,0 +1,3 @@
1
+ module JsonDeepCompare
2
+ VERSION = '0.2.0'
3
+ end
@@ -1,6 +1,6 @@
1
1
  require 'test/unit'
2
- $: << '.'
3
- require 'lib/json-deep-compare'
2
+ $: << 'lib'
3
+ require 'json-deep-compare'
4
4
 
5
5
  class DocumentComparisonTestCase < Test::Unit::TestCase
6
6
  def assert_symmetrically_different(
@@ -198,4 +198,13 @@ class DocumentComparisonTestCase < Test::Unit::TestCase
198
198
  )
199
199
  assert comparison.equal?
200
200
  end
201
+
202
+ def test_substitutions
203
+ lval = {'one' => 'two', 'three' => 'four'}
204
+ rval = {'one' => 'two', 'three' => 'THREE'}
205
+ comparison = JsonDeepCompare::DocumentComparison.new(
206
+ lval, rval, substitutions: {":root > .three" => 'THREE'}
207
+ )
208
+ assert comparison.equal?
209
+ end
201
210
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: json-deep-compare
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-02-01 00:00:00.000000000 Z
12
+ date: 2014-02-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -57,6 +57,10 @@ files:
57
57
  - Rakefile
58
58
  - json-deep-compare.gemspec
59
59
  - lib/json-deep-compare.rb
60
+ - lib/json-deep-compare/assertions.rb
61
+ - lib/json-deep-compare/document_comparison.rb
62
+ - lib/json-deep-compare/node_comparison.rb
63
+ - lib/json-deep-compare/version.rb
60
64
  - test/json_deep_compare_test.rb
61
65
  homepage: ''
62
66
  licenses:
@@ -73,7 +77,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
73
77
  version: '0'
74
78
  segments:
75
79
  - 0
76
- hash: 634763774305586060
80
+ hash: -2030263147861406758
77
81
  required_rubygems_version: !ruby/object:Gem::Requirement
78
82
  none: false
79
83
  requirements:
@@ -82,7 +86,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
82
86
  version: '0'
83
87
  segments:
84
88
  - 0
85
- hash: 634763774305586060
89
+ hash: -2030263147861406758
86
90
  requirements: []
87
91
  rubyforge_project:
88
92
  rubygems_version: 1.8.23