diff --git a/lib/octocatalog-diff/catalog-diff/differ.rb b/lib/octocatalog-diff/catalog-diff/differ.rb index 3d959fa0..83d21c86 100644 --- a/lib/octocatalog-diff/catalog-diff/differ.rb +++ b/lib/octocatalog-diff/catalog-diff/differ.rb @@ -628,9 +628,14 @@ def hashdiff_nested_changes(hashdiff_add_remove, remaining1, remaining2) def dig_out_key(hash_in, key_array) return hash_in if key_array.empty? return hash_in unless hash_in.is_a?(Hash) - return nil unless hash_in.key?(key_array[0]) - next_key = key_array.shift - dig_out_key(hash_in[next_key], key_array) + key_without_index = key_array[0].sub(/\[\d+\]/, '') + return nil unless hash_in.key?(key_without_index) + full_key = key_array.shift + next_obj = hash_in[key_without_index] + # jump into array index if needed + md = full_key.match(/\[(\d+)\]/) + next_obj = next_obj[md[1].to_i] if md + dig_out_key(next_obj, key_array) end # This is a helper for the constructor, verifying that the incoming catalog is an expected diff --git a/spec/octocatalog-diff/tests/catalog-diff/differ_spec.rb b/spec/octocatalog-diff/tests/catalog-diff/differ_spec.rb index 2287e076..91b2a0c0 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/differ_spec.rb +++ b/spec/octocatalog-diff/tests/catalog-diff/differ_spec.rb @@ -1481,6 +1481,88 @@ fileref = { 'file' => '/var/tmp/foo', 'line' => 5 } expect(result[0]).to eq(['!', "Class\fOpenssl::Package\fparameters\fcommon-array", [1, 2, 3], [1, 5, 25], fileref, fileref]) end + + it 'should return array with proper results for deeply nested arrays of hashes' do + hashdiff_add_remove = [ + "Class\fOpenssl::Package\fparameters\fobject\farray[0]\fcommon-array" + ] + + empty_puppet_catalog_json = File.read(OctocatalogDiff::Spec.fixture_path('catalogs/catalog-empty.json')) + empty_puppet_catalog = OctocatalogDiff::Catalog.create(json: empty_puppet_catalog_json) + obj = OctocatalogDiff::CatalogDiff::Differ.new({}, empty_puppet_catalog, empty_puppet_catalog) + + arr1 = [ + { + 'name' => 'test', 'value' => 'abc' + }, + { + 'name' => 'test2', 'value' => 'def' + } + ] + cat1 = [ + { + 'type' => 'Class', + 'title' => 'Openssl::Package', + 'parameters' => { + 'object' => { + 'array' => [ + { + 'common-array' => arr1 + } + ] + } + }, + 'file' => '/var/tmp/foo', + 'line' => 5 + } + ] + + arr2 = [ + { + 'name' => 'test', 'value' => 'abc' + }, + { + 'name' => 'test2', 'value' => 'def' + }, + { + 'name' => 'test3', 'value' => 'ghj' + } + ] + cat2 = [ + { + 'type' => 'Class', + 'title' => 'Openssl::Package', + 'parameters' => { + 'object' => { + 'array' => [ + { + 'common-array' => arr2 + } + ] + } + }, + 'file' => '/var/tmp/foo', + 'line' => 5 + } + ] + + remaining1 = obj.send(:resources_as_hashes_with_serialized_keys, cat1) + remaining2 = obj.send(:resources_as_hashes_with_serialized_keys, cat2) + + result = obj.send(:hashdiff_nested_changes, hashdiff_add_remove, remaining1, remaining2) + expect(result).to be_a_kind_of(Array) + expect(result.size).to eq(1) + + fileref = { 'file' => '/var/tmp/foo', 'line' => 5 } + expect(result[0]).to eq([ + '!', + "Class\fOpenssl::Package\fparameters\fobject\farray[0]\fcommon-array", + arr1, + arr2, + fileref, + fileref + ]) + end end describe '#regexp_operator_match?' do