structure_compare 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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