structure_compare 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/structure_compare.rb +4 -1
- data/lib/structure_compare/structure_comparison.rb +43 -21
- data/lib/structure_compare/version.rb +1 -1
- data/test/structure_compare_test.rb +31 -11
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 38ec4e210b5674286a4e88ea6011ae71facb4ebc
|
4
|
+
data.tar.gz: 65755bdd48627fa619460f2abe6142a179f3ac00
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 63c5810ee73f6325340d89ea0dfa99a1fbcf88f5c3270b413abf6d9e470597bd4e86b8497929109fe6cce157a774bfc9c3bc8df7ecd458ea503057e8338d3684
|
7
|
+
data.tar.gz: 4b0309d805073de85b67b74c6c497350fc21817e230301802b0c58eb84bfc0b3f1f27d601a661eaa4cda20e9d223160427d0fdeedda339fd499b84f26bbdbbf7
|
data/lib/structure_compare.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
# TODO: doc (interface, assertions, ...)
|
2
2
|
module StructureCompare
|
3
|
+
class ArgumentError < ::ArgumentError; end
|
4
|
+
class RuntimeError < ::RuntimeError; end
|
5
|
+
|
3
6
|
class StructuresNotEqualError < RuntimeError; end
|
4
|
-
class
|
7
|
+
class IndifferentAccessError < RuntimeError; end
|
5
8
|
end
|
6
9
|
|
7
10
|
require 'structure_compare/version'
|
@@ -5,7 +5,7 @@ module StructureCompare
|
|
5
5
|
@options = {
|
6
6
|
strict_key_order: false,
|
7
7
|
check_values: false,
|
8
|
-
|
8
|
+
indifferent_access: false,
|
9
9
|
float_tolerance_factor: 0
|
10
10
|
}.merge(options)
|
11
11
|
end
|
@@ -45,7 +45,7 @@ module StructureCompare
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def check_arrays_equal!(expected, actual)
|
48
|
-
|
48
|
+
check_values_equal!(
|
49
49
|
expected.count, actual.count, "array length: #{expected.count} != #{actual.count}"
|
50
50
|
)
|
51
51
|
|
@@ -61,48 +61,52 @@ module StructureCompare
|
|
61
61
|
def check_hashes_equal!(expected, actual)
|
62
62
|
check_hash_keys_equal!(expected, actual)
|
63
63
|
|
64
|
-
|
65
|
-
|
64
|
+
expected.each do |key, expected_value|
|
65
|
+
if @options[:indifferent_access]
|
66
|
+
actual_value = with_indifferent_access!(actual, key)
|
67
|
+
else
|
68
|
+
actual_value = actual[key]
|
69
|
+
end
|
66
70
|
|
67
|
-
expected_values.each_with_index do |expected_value, index|
|
68
|
-
key = expected.keys[index]
|
69
71
|
path_segment = key.is_a?(Symbol) ? "[:#{key}]" : "[\"#{key}\"]"
|
70
72
|
@path.push(path_segment)
|
71
73
|
|
72
|
-
check_structures_equal!(expected_value,
|
74
|
+
check_structures_equal!(expected_value, actual_value)
|
73
75
|
@path.pop
|
74
76
|
end
|
75
77
|
end
|
76
78
|
|
79
|
+
# TODO safeguard in case there's a key as symbol _and_ hash
|
77
80
|
def check_hash_keys_equal!(expected, actual)
|
78
81
|
expected_keys = expected.keys
|
79
82
|
actual_keys = actual.keys
|
80
83
|
|
81
|
-
if @options[:
|
84
|
+
if @options[:indifferent_access]
|
82
85
|
# NOTE: not all hash keys are symbols/strings, only convert symbols
|
83
86
|
expected_keys.map! { |key| key.is_a?(Symbol) ? key.to_s : key }
|
84
87
|
actual_keys.map! { |key| key.is_a?(Symbol) ? key.to_s : key }
|
85
88
|
end
|
86
89
|
|
90
|
+
failure_message = "hash keys aren't equal"
|
91
|
+
|
87
92
|
if @options[:strict_key_order]
|
88
|
-
|
93
|
+
if expected_keys != actual_keys
|
94
|
+
not_equal_error!(expected_keys, actual_keys, failure_message)
|
95
|
+
end
|
89
96
|
else
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
)
|
97
|
+
# NOTE: first did this with sorting, but can't sort mixed type keys
|
98
|
+
all_keys_present = (
|
99
|
+
expected_keys.all?{ |key| actual.has_key?(key) } &&
|
100
|
+
actual_keys.all?{ |key| expected.has_key?(key) }
|
101
|
+
)
|
102
|
+
if !all_keys_present
|
103
|
+
not_equal_error!(expected_keys, actual_keys, failure_message)
|
98
104
|
end
|
99
|
-
|
100
|
-
check_equal!(expected_keys, actual_keys)
|
101
105
|
end
|
102
106
|
end
|
103
107
|
|
104
108
|
def check_leafs_equal!(expected, actual)
|
105
|
-
|
109
|
+
check_values_equal!(expected, actual) if @options[:check_values]
|
106
110
|
end
|
107
111
|
|
108
112
|
def check_kind_of!(expected, actual)
|
@@ -112,7 +116,7 @@ module StructureCompare
|
|
112
116
|
end
|
113
117
|
end
|
114
118
|
|
115
|
-
def
|
119
|
+
def check_values_equal!(expected, actual, failure_message = nil)
|
116
120
|
if expected.is_a?(Float) && actual.is_a?(Float)
|
117
121
|
is_equal = float_equal_with_tolerance_factor?(
|
118
122
|
expected, actual, @options[:float_tolerance_factor]
|
@@ -141,5 +145,23 @@ module StructureCompare
|
|
141
145
|
@error = failure_message
|
142
146
|
raise StructuresNotEqualError.new() # TODO error message, path
|
143
147
|
end
|
148
|
+
|
149
|
+
def with_indifferent_access!(actual, key)
|
150
|
+
if [Symbol, String].include?(key.class)
|
151
|
+
has_both_types = (actual.has_key?(key) && actual.has_key?(key.to_s))
|
152
|
+
duplicate_key_error!(key) if has_both_types
|
153
|
+
|
154
|
+
actual.has_key?(key.to_s) ? actual[key.to_s] : actual[key.to_sym]
|
155
|
+
else
|
156
|
+
actual[key]
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def duplicate_key_error!(key)
|
161
|
+
raise StructureCompare::IndifferentAccessError.new(
|
162
|
+
"#{@path.join}: key is present as string and symbol. " \
|
163
|
+
"can not use indifferent_access option!"
|
164
|
+
)
|
165
|
+
end
|
144
166
|
end
|
145
167
|
end
|
@@ -39,6 +39,18 @@ class StructureCompareTest < MiniTest::Test
|
|
39
39
|
refute_structures_equal([1, 2], [1, 2, 3])
|
40
40
|
end
|
41
41
|
|
42
|
+
def test_with_strict_key_order_off_compares_correct_values
|
43
|
+
structure_a = { a: 1, b: 2 }
|
44
|
+
structure_b = { b: 2, a: 1 }
|
45
|
+
assert_structures_equal(
|
46
|
+
structure_a, structure_b, check_values: true, strict_key_order: false
|
47
|
+
)
|
48
|
+
|
49
|
+
structure_a = { a: { c: 1 }, b: 2 }
|
50
|
+
structure_b = { b: 2, a: { c: 1 } }
|
51
|
+
assert_structures_equal(structure_a, structure_b, strict_key_order: false)
|
52
|
+
end
|
53
|
+
|
42
54
|
def test_stores_error_with_path_in_getter
|
43
55
|
structure_a = { x: 1, a: [{ b: [1, 1, 1] }] }
|
44
56
|
structure_b = { x: 1, a: [{ b: [1, 9, 1] }] }
|
@@ -67,27 +79,35 @@ class StructureCompareTest < MiniTest::Test
|
|
67
79
|
refute_structures_equal(structure_a, structure_b, check_values: true)
|
68
80
|
end
|
69
81
|
|
70
|
-
|
82
|
+
# this was a bug where we compared keys by sorting them, resulting in
|
83
|
+
# an ArgumentError if keys weren't comparable (String vs. Fixnum)
|
84
|
+
def test_mixed_type_hash_works_if_strict_key_order_not_set
|
71
85
|
hash = { a: 1, 5 => 6 }
|
72
|
-
|
73
|
-
assert_raises StructureCompare::ArgumentError do
|
74
|
-
assert_structures_equal(hash, hash)
|
75
|
-
end
|
76
|
-
|
77
|
-
assert_structures_equal(hash, hash, strict_key_order: true)
|
86
|
+
assert_structures_equal(hash, hash, strict_key_order: false)
|
78
87
|
end
|
79
88
|
|
80
|
-
def
|
81
|
-
string_hash = {"a" => 1, "b" => 2, 5 => 6}
|
82
|
-
symbol_hash = {a: 1, b: 2, 5 => 6}
|
89
|
+
def test_indifferent_access_option_works_as_expected
|
90
|
+
string_hash = { "a" => 1, "b" => 2, 5 => 6 }
|
91
|
+
symbol_hash = { a: 1, b: 2, 5 => 6 }
|
83
92
|
|
84
93
|
refute_structures_equal(string_hash, symbol_hash, strict_key_order: true)
|
85
94
|
assert_structures_equal(
|
86
95
|
string_hash, symbol_hash,
|
87
|
-
|
96
|
+
indifferent_access: true, strict_key_order: true
|
88
97
|
)
|
89
98
|
end
|
90
99
|
|
100
|
+
def test_option_for_indifferent_access_raises_if_symbol_and_string_key_present
|
101
|
+
hash = { "a" => 1, a: 2 }
|
102
|
+
assert_structures_equal(hash, hash, strict_key_order: true)
|
103
|
+
|
104
|
+
assert_raises StructureCompare::IndifferentAccessError do
|
105
|
+
assert_structures_equal(
|
106
|
+
hash, hash, strict_key_order: true, indifferent_access: true
|
107
|
+
)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
91
111
|
def test_compares_floats_correctly
|
92
112
|
assert_structures_equal([1.0, 2.0, 3.0], [1.0, 2.0, 3.0], check_values: true)
|
93
113
|
assert_structures_equal(
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: structure_compare
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Markus Seeger
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-05-
|
11
|
+
date: 2015-05-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|