structure_compare 0.1.0 → 0.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 535404ee3a6c198af0c7788bee7f0a31d15fee6c
4
- data.tar.gz: c133617419e3d5b8e3338e63ae08b123b74a3ad3
3
+ metadata.gz: 7ebebf0cb0eafd7f627df962d71f2553c3de2d62
4
+ data.tar.gz: 3a858990738e61837a4a47d0497667ba94dacf52
5
5
  SHA512:
6
- metadata.gz: 4decfee7c6aafed708585478a69be43475a2a52db8b1484bc179df16c53610f7c47dbf98b77a8d0249615f9a9d5832b882ad1c4d0235b3cffb9b1bdbb506693c
7
- data.tar.gz: 78f2b98c8c8af06034ffada10178cd343ee479e4004732caff6a8bb70f47ae122fe299755d5247435e8389ca7c62158cc91a0d45a0a3d36716fae96f6d6c5c14
6
+ metadata.gz: b4e814993fe0e4fe32345c1908f739f337aea61fb6880387bdc33d76245925e9e485a0ab06278ebcdefa5bfd9fc4e2487eef1b272bd160a0e216ab800b42ea2b
7
+ data.tar.gz: 643bb740f4c6e0392c06cb5b17f812329fa36b008446a14f2997661a5a9719e66c971ffe727bdb10ef1295e9bdc2ea75474a77c07c3b6b5c7a5156760cb571ae
@@ -1,156 +1,8 @@
1
- # TODO rename to structure_compare
2
- # TODO Enumerable to support non-array enumerables
3
- # TODO doc
1
+ # TODO: doc (interface, assertions, ...)
4
2
  module StructureCompare
5
-
6
3
  class StructuresNotEqualError < RuntimeError; end
7
4
  class ArgumentError < ArgumentError; end
8
-
9
- class StructureComparison
10
- def initialize(options = {})
11
- @options = {
12
- strict_key_order: false,
13
- check_values: false,
14
- treat_hash_symbols_as_strings: false,
15
- float_tolerance_factor: 0
16
- }.merge(options)
17
- end
18
-
19
- # TODO doc
20
- def structures_are_equal?(expected, actual)
21
- @path = []
22
- @error = nil
23
-
24
- begin
25
- check_structures_equal!(expected, actual)
26
- rescue StructuresNotEqualError => _error
27
- return false
28
- end
29
-
30
- return true
31
- end
32
-
33
- # TODO doc
34
- def error
35
- "#{@path.join} : #{@error}"
36
- end
37
-
38
- protected
39
-
40
- def check_structures_equal!(expected, actual)
41
- check_kind_of!(expected, actual)
42
-
43
- case expected
44
- when Array
45
- check_arrays_equal!(expected, actual)
46
- when Hash
47
- check_hashes_equal!(expected, actual)
48
- else
49
- check_leafs_equal!(expected, actual)
50
- end
51
- end
52
-
53
- def check_arrays_equal!(expected, actual)
54
- check_equal!(
55
- expected.count, actual.count, "array length: #{expected.count} != #{actual.count}"
56
- )
57
-
58
- expected.each_with_index do |expected_value, index|
59
- path_segment = "[#{index}]"
60
- @path.push(path_segment)
61
-
62
- check_structures_equal!(expected_value, actual[index])
63
- @path.pop
64
- end
65
- end
66
-
67
- def check_hashes_equal!(expected, actual)
68
- check_hash_keys_equal!(expected, actual)
69
-
70
- expected_values = expected.values
71
- actual_values = actual.values
72
-
73
- expected_values.each_with_index do |expected_value, index|
74
- key = expected.keys[index]
75
- path_segment = key.is_a?(Symbol) ? "[:#{key}]" : "[\"#{key}\"]"
76
- @path.push(path_segment)
77
-
78
- check_structures_equal!(expected_value, actual_values[index])
79
- @path.pop
80
- end
81
- end
82
-
83
- def check_hash_keys_equal!(expected, actual)
84
- expected_keys = expected.keys
85
- actual_keys = actual.keys
86
-
87
- if @options[:treat_hash_symbols_as_strings]
88
- # NOTE: not all hash keys are symbols/strings, only convert symbols
89
- expected_keys.map! { |key| key.is_a?(Symbol) ? key.to_s : key }
90
- actual_keys.map! { |key| key.is_a?(Symbol) ? key.to_s : key }
91
- end
92
-
93
- if @options[:strict_key_order]
94
- check_equal!(expected_keys, actual_keys)
95
- else
96
- begin
97
- expected_keys.sort!
98
- actual_keys.sort!
99
- rescue ::ArgumentError => error
100
- raise StructureCompare::ArgumentError.new(
101
- "Unable to sort hash keys: \"#{error}\"." +
102
- 'Try enabling :strict_key_order option to prevent sorting of mixed-type hash keys.'
103
- )
104
- end
105
-
106
- check_equal!(expected_keys, actual_keys)
107
- end
108
- end
109
-
110
- def check_leafs_equal!(expected, actual)
111
- check_equal!(expected, actual) if @options[:check_values]
112
- end
113
-
114
- def check_kind_of!(expected, actual)
115
- unless actual.kind_of?(expected.class)
116
- failure_message = "expected #{actual.class.to_s} to be kind of #{expected.class.to_s}"
117
- not_equal_error!(expected, actual, failure_message)
118
- end
119
- end
120
-
121
- def check_equal!(expected, actual, failure_message = nil)
122
- if expected.is_a?(Float) && actual.is_a?(Float)
123
- is_equal = float_equal_with_tolerance_factor?(
124
- expected, actual, @options[:float_tolerance_factor]
125
- )
126
- else
127
- is_equal = (expected == actual)
128
- end
129
-
130
- if !is_equal
131
- failure_message ||= "expected: #{expected.inspect}, got: #{actual.inspect}"
132
- not_equal_error!(expected, actual, failure_message)
133
- end
134
- end
135
-
136
- def float_equal_with_tolerance_factor?(expected, actual, tolerance_factor)
137
- raise StructureCompare::ArgumentError.new("tolerance_factor must be > 0") if tolerance_factor < 0
138
-
139
- lower_bound = (expected * (1.0 - tolerance_factor) - Float::EPSILON)
140
- upper_bound = (expected * (1.0 + tolerance_factor) + Float::EPSILON)
141
-
142
- return (lower_bound <= actual) && (actual <= upper_bound)
143
- end
144
-
145
- # TODO make this part of an overridden exception?
146
- def not_equal_error!(expected, actual, failure_message)
147
- @error = failure_message
148
- raise StructuresNotEqualError.new() # TODO error message, path
149
- end
150
- end
151
-
152
5
  end
153
6
 
154
- # TODO test if monkeypatching MiniTest::Assertions works
155
-
156
- require 'version'
7
+ require 'structure_compare/version'
8
+ require 'structure_compare/structure_comparison'
@@ -0,0 +1,16 @@
1
+ class Minitest::Test
2
+
3
+ protected
4
+
5
+ def assert_structures_equal(expected, actual, options = {})
6
+ comparison = StructureCompare::StructureComparison.new(options)
7
+ is_equal = comparison.structures_are_equal?(expected, actual)
8
+ assert is_equal, comparison.error
9
+ end
10
+
11
+ def refute_structures_equal(expected, actual, options = {})
12
+ comparison = StructureCompare::StructureComparison.new(options)
13
+ is_equal = comparison.structures_are_equal?(expected, actual)
14
+ refute is_equal, "structures are not expected to be equal"
15
+ end
16
+ end
@@ -0,0 +1,145 @@
1
+ module StructureCompare
2
+ # TODO: Enumerable to support non-array enumerables
3
+ class StructureComparison
4
+ def initialize(options = {})
5
+ @options = {
6
+ strict_key_order: false,
7
+ check_values: false,
8
+ treat_hash_symbols_as_strings: false,
9
+ float_tolerance_factor: 0
10
+ }.merge(options)
11
+ end
12
+
13
+ # TODO doc
14
+ def structures_are_equal?(expected, actual)
15
+ @path = []
16
+ @error = nil
17
+
18
+ begin
19
+ check_structures_equal!(expected, actual)
20
+ rescue StructuresNotEqualError => _error
21
+ return false
22
+ end
23
+
24
+ return true
25
+ end
26
+
27
+ # TODO doc
28
+ def error
29
+ "#{@path.join} : #{@error}"
30
+ end
31
+
32
+ protected
33
+
34
+ def check_structures_equal!(expected, actual)
35
+ check_kind_of!(expected, actual)
36
+
37
+ case expected
38
+ when Array
39
+ check_arrays_equal!(expected, actual)
40
+ when Hash
41
+ check_hashes_equal!(expected, actual)
42
+ else
43
+ check_leafs_equal!(expected, actual)
44
+ end
45
+ end
46
+
47
+ def check_arrays_equal!(expected, actual)
48
+ check_equal!(
49
+ expected.count, actual.count, "array length: #{expected.count} != #{actual.count}"
50
+ )
51
+
52
+ expected.each_with_index do |expected_value, index|
53
+ path_segment = "[#{index}]"
54
+ @path.push(path_segment)
55
+
56
+ check_structures_equal!(expected_value, actual[index])
57
+ @path.pop
58
+ end
59
+ end
60
+
61
+ def check_hashes_equal!(expected, actual)
62
+ check_hash_keys_equal!(expected, actual)
63
+
64
+ expected_values = expected.values
65
+ actual_values = actual.values
66
+
67
+ expected_values.each_with_index do |expected_value, index|
68
+ key = expected.keys[index]
69
+ path_segment = key.is_a?(Symbol) ? "[:#{key}]" : "[\"#{key}\"]"
70
+ @path.push(path_segment)
71
+
72
+ check_structures_equal!(expected_value, actual_values[index])
73
+ @path.pop
74
+ end
75
+ end
76
+
77
+ def check_hash_keys_equal!(expected, actual)
78
+ expected_keys = expected.keys
79
+ actual_keys = actual.keys
80
+
81
+ if @options[:treat_hash_symbols_as_strings]
82
+ # NOTE: not all hash keys are symbols/strings, only convert symbols
83
+ expected_keys.map! { |key| key.is_a?(Symbol) ? key.to_s : key }
84
+ actual_keys.map! { |key| key.is_a?(Symbol) ? key.to_s : key }
85
+ end
86
+
87
+ if @options[:strict_key_order]
88
+ check_equal!(expected_keys, actual_keys)
89
+ else
90
+ begin
91
+ expected_keys.sort!
92
+ actual_keys.sort!
93
+ rescue ::ArgumentError => error
94
+ raise StructureCompare::ArgumentError.new(
95
+ "Unable to sort hash keys: \"#{error}\"." +
96
+ 'Try enabling :strict_key_order option to prevent sorting of mixed-type hash keys.'
97
+ )
98
+ end
99
+
100
+ check_equal!(expected_keys, actual_keys)
101
+ end
102
+ end
103
+
104
+ def check_leafs_equal!(expected, actual)
105
+ check_equal!(expected, actual) if @options[:check_values]
106
+ end
107
+
108
+ def check_kind_of!(expected, actual)
109
+ unless actual.kind_of?(expected.class)
110
+ failure_message = "expected #{actual.class.to_s} to be kind of #{expected.class.to_s}"
111
+ not_equal_error!(expected, actual, failure_message)
112
+ end
113
+ end
114
+
115
+ def check_equal!(expected, actual, failure_message = nil)
116
+ if expected.is_a?(Float) && actual.is_a?(Float)
117
+ is_equal = float_equal_with_tolerance_factor?(
118
+ expected, actual, @options[:float_tolerance_factor]
119
+ )
120
+ else
121
+ is_equal = (expected == actual)
122
+ end
123
+
124
+ if !is_equal
125
+ failure_message ||= "expected: #{expected.inspect}, got: #{actual.inspect}"
126
+ not_equal_error!(expected, actual, failure_message)
127
+ end
128
+ end
129
+
130
+ def float_equal_with_tolerance_factor?(expected, actual, tolerance_factor)
131
+ raise StructureCompare::ArgumentError.new("tolerance_factor must be > 0") if tolerance_factor < 0
132
+
133
+ lower_bound = (expected * (1.0 - tolerance_factor) - Float::EPSILON)
134
+ upper_bound = (expected * (1.0 + tolerance_factor) + Float::EPSILON)
135
+
136
+ return (lower_bound <= actual) && (actual <= upper_bound)
137
+ end
138
+
139
+ # TODO make this part of an overridden exception?
140
+ def not_equal_error!(expected, actual, failure_message)
141
+ @error = failure_message
142
+ raise StructuresNotEqualError.new() # TODO error message, path
143
+ end
144
+ end
145
+ end
@@ -1,3 +1,3 @@
1
1
  module StructureCompare
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
@@ -1,7 +1,7 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  lib = File.expand_path('../lib', __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'version'
4
+ require 'structure_compare/version'
5
5
 
6
6
  Gem::Specification.new do |gem|
7
7
  gem.name = "structure_compare"
@@ -1,5 +1,6 @@
1
1
  require_relative "test_helper"
2
- require_relative "../lib/structure_compare"
2
+ require_relative '../lib/structure_compare'
3
+ require_relative '../lib/structure_compare/minitest'
3
4
 
4
5
  class StructureCompareTest < MiniTest::Test
5
6
 
@@ -158,19 +159,4 @@ class StructureCompareTest < MiniTest::Test
158
159
  )
159
160
  end
160
161
  end
161
-
162
- protected
163
-
164
- def assert_structures_equal(expected, actual, options = {})
165
- comparison = StructureCompare::StructureComparison.new(options)
166
- is_equal = comparison.structures_are_equal?(expected, actual)
167
- assert is_equal, comparison.error
168
- end
169
-
170
- def refute_structures_equal(expected, actual, options = {})
171
- comparison = StructureCompare::StructureComparison.new(options)
172
- is_equal = comparison.structures_are_equal?(expected, actual)
173
- refute is_equal, "structures are not expected to be equal"
174
- end
175
-
176
162
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: structure_compare
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Markus Seeger
@@ -123,7 +123,9 @@ files:
123
123
  - README.md
124
124
  - Rakefile
125
125
  - lib/structure_compare.rb
126
- - lib/version.rb
126
+ - lib/structure_compare/minitest.rb
127
+ - lib/structure_compare/structure_comparison.rb
128
+ - lib/structure_compare/version.rb
127
129
  - structure_compare.gemspec
128
130
  - test/structure_compare_test.rb
129
131
  - test/test_helper.rb