json-deep-compare 0.1.0 → 0.2.0

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.
@@ -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