From c8b53719a266e0aff8f19d4a2313e97eee16834a Mon Sep 17 00:00:00 2001 From: Steven Danna Date: Sat, 8 Feb 2014 20:21:03 -0800 Subject: [CHEF-4918] Don't destructively merge subhashes in hash_only_merge! hash_only_merge dups its inputs and then passes it to hash_only_merge!. Unfortunately, dup does not make a deep copy, leading hash_only_merge to mutate deeply nested structures. --- lib/chef/mixin/deep_merge.rb | 8 +++++--- spec/unit/mixin/deep_merge_spec.rb | 7 +++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/chef/mixin/deep_merge.rb b/lib/chef/mixin/deep_merge.rb index ad3e5803fd..5002f5dcc5 100644 --- a/lib/chef/mixin/deep_merge.rb +++ b/lib/chef/mixin/deep_merge.rb @@ -122,7 +122,11 @@ class Chef # If there are two Hashes, recursively merge. if merge_onto.kind_of?(Hash) && merge_with.kind_of?(Hash) merge_with.each do |key, merge_with_value| - merge_onto[key] = hash_only_merge!(merge_onto[key], merge_with_value) + merge_onto[key] = if merge_onto.has_key?(key) + hash_only_merge(merge_onto[key], merge_with_value) + else + merge_with_value + end end merge_onto @@ -164,5 +168,3 @@ class Chef end end end - - diff --git a/spec/unit/mixin/deep_merge_spec.rb b/spec/unit/mixin/deep_merge_spec.rb index 0a7bbffa41..b7828a3076 100644 --- a/spec/unit/mixin/deep_merge_spec.rb +++ b/spec/unit/mixin/deep_merge_spec.rb @@ -347,5 +347,12 @@ describe Chef::Mixin::DeepMerge do merged_result["top_level_a"]["1_deep_b"].should == %w[B B B] end + it "does not mutate deeply-nested original hashes by default" do + merge_ee_hash = {"top_level_a" => {"1_deep_a" => { "2_deep_a" => { "3_deep_a" => "foo" }}}} + merge_with_hash = {"top_level_a" => {"1_deep_a" => { "2_deep_a" => { "3_deep_b" => "bar" }}}} + @dm.hash_only_merge(merge_ee_hash, merge_with_hash) + merge_ee_hash.should == {"top_level_a" => {"1_deep_a" => { "2_deep_a" => { "3_deep_a" => "foo" }}}} + merge_with_hash.should == {"top_level_a" => {"1_deep_a" => { "2_deep_a" => { "3_deep_b" => "bar" }}}} + end end end -- cgit v1.2.1