structure_compare 0.1.1 → 0.1.2

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: 7ebebf0cb0eafd7f627df962d71f2553c3de2d62
4
- data.tar.gz: 3a858990738e61837a4a47d0497667ba94dacf52
3
+ metadata.gz: 38ec4e210b5674286a4e88ea6011ae71facb4ebc
4
+ data.tar.gz: 65755bdd48627fa619460f2abe6142a179f3ac00
5
5
  SHA512:
6
- metadata.gz: b4e814993fe0e4fe32345c1908f739f337aea61fb6880387bdc33d76245925e9e485a0ab06278ebcdefa5bfd9fc4e2487eef1b272bd160a0e216ab800b42ea2b
7
- data.tar.gz: 643bb740f4c6e0392c06cb5b17f812329fa36b008446a14f2997661a5a9719e66c971ffe727bdb10ef1295e9bdc2ea75474a77c07c3b6b5c7a5156760cb571ae
6
+ metadata.gz: 63c5810ee73f6325340d89ea0dfa99a1fbcf88f5c3270b413abf6d9e470597bd4e86b8497929109fe6cce157a774bfc9c3bc8df7ecd458ea503057e8338d3684
7
+ data.tar.gz: 4b0309d805073de85b67b74c6c497350fc21817e230301802b0c58eb84bfc0b3f1f27d601a661eaa4cda20e9d223160427d0fdeedda339fd499b84f26bbdbbf7
@@ -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 ArgumentError < ArgumentError; end
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
- treat_hash_symbols_as_strings: false,
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
- check_equal!(
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
- expected_values = expected.values
65
- actual_values = actual.values
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, actual_values[index])
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[:treat_hash_symbols_as_strings]
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
- check_equal!(expected_keys, actual_keys)
93
+ if expected_keys != actual_keys
94
+ not_equal_error!(expected_keys, actual_keys, failure_message)
95
+ end
89
96
  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
- )
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
- check_equal!(expected, actual) if @options[:check_values]
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 check_equal!(expected, actual, failure_message = nil)
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
@@ -1,3 +1,3 @@
1
1
  module StructureCompare
2
- VERSION = "0.1.1"
2
+ VERSION = "0.1.2"
3
3
  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
- def test_mixed_type_hash_keys_trigger_error_unless_strict_order_set
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 test_symbol_keys_are_strings_if_option_set
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
- treat_hash_symbols_as_strings: true, strict_key_order: true
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.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-20 00:00:00.000000000 Z
11
+ date: 2015-05-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake