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