summaryrefslogtreecommitdiff
path: root/spec/unit/node/vivid_mash_spec.rb
diff options
context:
space:
mode:
Diffstat (limited to 'spec/unit/node/vivid_mash_spec.rb')
-rw-r--r--spec/unit/node/vivid_mash_spec.rb255
1 files changed, 168 insertions, 87 deletions
diff --git a/spec/unit/node/vivid_mash_spec.rb b/spec/unit/node/vivid_mash_spec.rb
index 5319ba4a35..834b9864f8 100644
--- a/spec/unit/node/vivid_mash_spec.rb
+++ b/spec/unit/node/vivid_mash_spec.rb
@@ -1,5 +1,5 @@
#
-# Copyright:: Copyright 2016, Chef Software Inc.
+# Copyright:: Copyright (c) Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,202 +19,212 @@ require "spec_helper"
require "chef/node/attribute_collections"
describe Chef::Node::VividMash do
- class Root
- attr_accessor :top_level_breadcrumb
- end
-
- let(:root) { Root.new }
+ let(:root) { instance_double(Chef::Node::Attribute) }
let(:vivid) do
- expect(root).to receive(:reset_cache).at_least(:once).with(nil)
- Chef::Node::VividMash.new(root,
- { "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ], "nil" => nil }
+ Chef::Node::VividMash.new(
+ { "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ], "nil" => nil },
+ root
)
end
- def with_breadcrumb(key)
- expect(root).to receive(:top_level_breadcrumb=).with(nil).at_least(:once).and_call_original
- expect(root).to receive(:top_level_breadcrumb=).with(key).at_least(:once).and_call_original
+ context "without a root node" do
+ let(:vivid) do
+ Chef::Node::VividMash.new(
+ { "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ], "nil" => nil }
+ )
+ end
+
+ it "sets the root to the root object" do
+ expect(vivid["one"]["two"].__root__).to eql(vivid)
+ end
+
+ it "does not send reset cache" do
+ # if we setup the expectation here then the object winds up responding to :reset_cache and then it fails...
+ # expect(vivid).not_to receive(:reset_cache)
+ # but even so we expect to blow up here with NoMethodError if we screw up and send :reset_cache to a root VividMash
+ vivid["one"]["foo"] = "bar"
+ end
+ end
+
+ context "#[]" do
+ it "works with array slices" do
+ expect(vivid["array"][1, 2]).to eql([1, 2])
+ end
+ end
+
+ context "#[]=" do
+ it "works with array slices" do
+ vivid["array"][3, 2] = [ 3, 4 ]
+ expect(vivid["array"]).to eql([0, 1, 2, 3, 4])
+ end
+
+ it "deep converts values through arrays" do
+ expect(root).to receive(:reset_cache).with("foo")
+ vivid["foo"] = [ { bar: true } ]
+ expect(vivid["foo"].class).to eql(Chef::Node::AttrArray)
+ expect(vivid["foo"][0].class).to eql(Chef::Node::VividMash)
+ expect(vivid["foo"][0]["bar"]).to be true
+ end
+
+ it "deep converts values through nested arrays" do
+ expect(root).to receive(:reset_cache).with("foo")
+ vivid["foo"] = [ [ { bar: true } ] ]
+ expect(vivid["foo"].class).to eql(Chef::Node::AttrArray)
+ expect(vivid["foo"][0].class).to eql(Chef::Node::AttrArray)
+ expect(vivid["foo"][0][0].class).to eql(Chef::Node::VividMash)
+ expect(vivid["foo"][0][0]["bar"]).to be true
+ end
+
+ it "deep converts values through hashes" do
+ expect(root).to receive(:reset_cache).with("foo")
+ vivid["foo"] = { baz: { bar: true } }
+ expect(vivid["foo"]).to be_an_instance_of(Chef::Node::VividMash)
+ expect(vivid["foo"]["baz"]).to be_an_instance_of(Chef::Node::VividMash)
+ expect(vivid["foo"]["baz"]["bar"]).to be true
+ end
end
context "#read" do
before do
- # vivify the vividmash, then we're read-only so the cache should never be cleared afterwards
- vivid
expect(root).not_to receive(:reset_cache)
end
it "reads hashes deeply" do
- with_breadcrumb("one")
expect(vivid.read("one", "two", "three")).to eql("four")
end
it "does not trainwreck when hitting hash keys that do not exist" do
- with_breadcrumb("one")
expect(vivid.read("one", "five", "six")).to eql(nil)
end
it "does not trainwreck when hitting an array with an out of bounds index" do
- with_breadcrumb("array")
expect(vivid.read("array", 5, "one")).to eql(nil)
end
it "does not trainwreck when hitting an array with a string key" do
- with_breadcrumb("array")
expect(vivid.read("array", "one", "two")).to eql(nil)
end
it "does not trainwreck when traversing a nil" do
- with_breadcrumb("nil")
expect(vivid.read("nil", "one", "two")).to eql(nil)
end
end
context "#exist?" do
before do
- # vivify the vividmash, then we're read-only so the cache should never be cleared afterwards
- vivid
expect(root).not_to receive(:reset_cache)
end
it "true if there's a hash key there" do
- with_breadcrumb("one")
expect(vivid.exist?("one", "two", "three")).to be true
end
it "true for intermediate hashes" do
- with_breadcrumb("one")
expect(vivid.exist?("one")).to be true
end
it "true for arrays that exist" do
- with_breadcrumb("array")
expect(vivid.exist?("array", 1)).to be true
end
it "true when the value of the key is nil" do
- with_breadcrumb("nil")
expect(vivid.exist?("nil")).to be true
end
it "false when attributes don't exist" do
- with_breadcrumb("one")
expect(vivid.exist?("one", "five", "six")).to be false
end
it "false when traversing a non-container" do
- with_breadcrumb("one")
expect(vivid.exist?("one", "two", "three", "four")).to be false
end
it "false when an array index does not exist" do
- with_breadcrumb("array")
expect(vivid.exist?("array", 3)).to be false
end
it "false when traversing a nil" do
- with_breadcrumb("nil")
expect(vivid.exist?("nil", "foo", "bar")).to be false
end
end
context "#read!" do
before do
- # vivify the vividmash, then we're read-only so the cache should never be cleared afterwards
- vivid
expect(root).not_to receive(:reset_cache)
end
it "reads hashes deeply" do
- with_breadcrumb("one")
expect(vivid.read!("one", "two", "three")).to eql("four")
end
it "reads arrays deeply" do
- with_breadcrumb("array")
expect(vivid.read!("array", 1)).to eql(1)
end
it "throws an exception when attributes do not exist" do
- with_breadcrumb("one")
- expect { vivid.read!("one", "five", "six") }.to raise_error(Chef::Exceptions::NoSuchAttribute)
+ expect { vivid.read!("one", "five", "six") }.to raise_error(Chef::Exceptions::NoSuchAttribute, "one.five.six")
end
it "throws an exception when traversing a non-container" do
- with_breadcrumb("one")
- expect { vivid.read!("one", "two", "three", "four") }.to raise_error(Chef::Exceptions::NoSuchAttribute)
+ expect { vivid.read!("one", "two", "three", "four") }.to raise_error(Chef::Exceptions::NoSuchAttribute, "one.two.three.four")
end
it "throws an exception when an array element does not exist" do
- with_breadcrumb("array")
- expect { vivid.read!("array", 3) }.to raise_error(Chef::Exceptions::NoSuchAttribute)
+ expect { vivid.read!("array", 3) }.to raise_error(Chef::Exceptions::NoSuchAttribute, "array.3")
end
end
context "#write" do
- before do
- vivid
- expect(root).not_to receive(:reset_cache).with(nil)
- end
-
it "should write into hashes" do
- with_breadcrumb("one")
expect(root).to receive(:reset_cache).at_least(:once).with("one")
vivid.write("one", "five", "six")
expect(vivid["one"]["five"]).to eql("six")
end
it "should deeply autovivify" do
- with_breadcrumb("one")
expect(root).to receive(:reset_cache).at_least(:once).with("one")
vivid.write("one", "five", "six", "seven", "eight", "nine", "ten")
expect(vivid["one"]["five"]["six"]["seven"]["eight"]["nine"]).to eql("ten")
end
it "should raise an exception if you overwrite an array with a hash" do
- with_breadcrumb("array")
expect(root).to receive(:reset_cache).at_least(:once).with("array")
vivid.write("array", "five", "six")
expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => { "five" => "six" }, "nil" => nil })
end
it "should raise an exception if you traverse through an array with a hash" do
- with_breadcrumb("array")
expect(root).to receive(:reset_cache).at_least(:once).with("array")
vivid.write("array", "five", "six", "seven")
expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => { "five" => { "six" => "seven" } }, "nil" => nil })
end
it "should raise an exception if you overwrite a string with a hash" do
- with_breadcrumb("one")
expect(root).to receive(:reset_cache).at_least(:once).with("one")
vivid.write("one", "two", "three", "four", "five")
expect(vivid).to eql({ "one" => { "two" => { "three" => { "four" => "five" } } }, "array" => [ 0, 1, 2 ], "nil" => nil })
end
it "should raise an exception if you traverse through a string with a hash" do
- with_breadcrumb("one")
expect(root).to receive(:reset_cache).at_least(:once).with("one")
vivid.write("one", "two", "three", "four", "five", "six")
expect(vivid).to eql({ "one" => { "two" => { "three" => { "four" => { "five" => "six" } } } }, "array" => [ 0, 1, 2 ], "nil" => nil })
end
it "should raise an exception if you overwrite a nil with a hash" do
- with_breadcrumb("nil")
expect(root).to receive(:reset_cache).at_least(:once).with("nil")
vivid.write("nil", "one", "two")
expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ], "nil" => { "one" => "two" } })
end
it "should raise an exception if you traverse through a nil with a hash" do
- with_breadcrumb("nil")
expect(root).to receive(:reset_cache).at_least(:once).with("nil")
vivid.write("nil", "one", "two", "three")
expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ], "nil" => { "one" => { "two" => "three" } } })
end
it "writes with a block" do
- with_breadcrumb("one")
expect(root).to receive(:reset_cache).at_least(:once).with("one")
vivid.write("one", "five") { "six" }
expect(vivid["one"]["five"]).to eql("six")
@@ -222,69 +232,55 @@ describe Chef::Node::VividMash do
end
context "#write!" do
- before do
- vivid
- expect(root).not_to receive(:reset_cache).with(nil)
- end
-
it "should write into hashes" do
- with_breadcrumb("one")
expect(root).to receive(:reset_cache).at_least(:once).with("one")
vivid.write!("one", "five", "six")
expect(vivid["one"]["five"]).to eql("six")
end
it "should deeply autovivify" do
- with_breadcrumb("one")
expect(root).to receive(:reset_cache).at_least(:once).with("one")
vivid.write!("one", "five", "six", "seven", "eight", "nine", "ten")
expect(vivid["one"]["five"]["six"]["seven"]["eight"]["nine"]).to eql("ten")
end
it "should raise an exception if you overwrite an array with a hash" do
- with_breadcrumb("array")
expect(root).not_to receive(:reset_cache)
expect { vivid.write!("array", "five", "six") }.to raise_error(Chef::Exceptions::AttributeTypeMismatch)
expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ], "nil" => nil })
end
it "should raise an exception if you traverse through an array with a hash" do
- with_breadcrumb("array")
expect(root).not_to receive(:reset_cache)
expect { vivid.write!("array", "five", "six", "seven") }.to raise_error(Chef::Exceptions::AttributeTypeMismatch)
expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ], "nil" => nil })
end
it "should raise an exception if you overwrite a string with a hash" do
- with_breadcrumb("one")
expect(root).not_to receive(:reset_cache)
expect { vivid.write!("one", "two", "three", "four", "five") }.to raise_error(Chef::Exceptions::AttributeTypeMismatch)
expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ], "nil" => nil })
end
it "should raise an exception if you traverse through a string with a hash" do
- with_breadcrumb("one")
expect(root).not_to receive(:reset_cache)
expect { vivid.write!("one", "two", "three", "four", "five", "six") }.to raise_error(Chef::Exceptions::AttributeTypeMismatch)
expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ], "nil" => nil })
end
it "should raise an exception if you overwrite a nil with a hash" do
- with_breadcrumb("nil")
expect(root).not_to receive(:reset_cache)
expect { vivid.write!("nil", "one", "two") }.to raise_error(Chef::Exceptions::AttributeTypeMismatch)
expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ], "nil" => nil })
end
it "should raise an exception if you traverse through a nil with a hash" do
- with_breadcrumb("nil")
expect(root).not_to receive(:reset_cache)
expect { vivid.write!("nil", "one", "two", "three") }.to raise_error(Chef::Exceptions::AttributeTypeMismatch)
expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ], "nil" => nil })
end
it "writes with a block" do
- with_breadcrumb("one")
expect(root).to receive(:reset_cache).at_least(:once).with("one")
vivid.write!("one", "five") { "six" }
expect(vivid["one"]["five"]).to eql("six")
@@ -292,41 +288,31 @@ describe Chef::Node::VividMash do
end
context "#unlink" do
- before do
- vivid
- expect(root).not_to receive(:reset_cache).with(nil)
- end
-
it "should return nil if the keys don't already exist" do
- expect(root).to receive(:top_level_breadcrumb=).with(nil).at_least(:once).and_call_original
expect(root).not_to receive(:reset_cache)
expect(vivid.unlink("five", "six", "seven", "eight")).to eql(nil)
expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ], "nil" => nil })
end
it "should unlink hashes" do
- with_breadcrumb("one")
expect(root).to receive(:reset_cache).at_least(:once).with("one")
expect( vivid.unlink("one") ).to eql({ "two" => { "three" => "four" } })
expect(vivid).to eql({ "array" => [ 0, 1, 2 ], "nil" => nil })
end
it "should unlink array elements" do
- with_breadcrumb("array")
expect(root).to receive(:reset_cache).at_least(:once).with("array")
expect(vivid.unlink("array", 2)).to eql(2)
expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1 ], "nil" => nil })
end
it "should unlink nil" do
- with_breadcrumb("nil")
expect(root).to receive(:reset_cache).at_least(:once).with("nil")
expect(vivid.unlink("nil")).to eql(nil)
expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ] })
end
it "should traverse a nil and safely do nothing" do
- with_breadcrumb("nil")
expect(root).not_to receive(:reset_cache)
expect(vivid.unlink("nil", "foo")).to eql(nil)
expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ], "nil" => nil })
@@ -334,44 +320,139 @@ describe Chef::Node::VividMash do
end
context "#unlink!" do
- before do
- vivid
- expect(root).not_to receive(:reset_cache).with(nil)
- end
-
it "should raise an exception if the keys don't already exist" do
- expect(root).to receive(:top_level_breadcrumb=).with(nil).at_least(:once).and_call_original
expect(root).not_to receive(:reset_cache)
expect { vivid.unlink!("five", "six", "seven", "eight") }.to raise_error(Chef::Exceptions::NoSuchAttribute)
expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ], "nil" => nil })
end
it "should unlink! hashes" do
- with_breadcrumb("one")
expect(root).to receive(:reset_cache).at_least(:once).with("one")
expect( vivid.unlink!("one") ).to eql({ "two" => { "three" => "four" } })
expect(vivid).to eql({ "array" => [ 0, 1, 2 ], "nil" => nil })
end
it "should unlink! array elements" do
- with_breadcrumb("array")
expect(root).to receive(:reset_cache).at_least(:once).with("array")
expect(vivid.unlink!("array", 2)).to eql(2)
expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1 ], "nil" => nil })
end
it "should unlink! nil" do
- with_breadcrumb("nil")
expect(root).to receive(:reset_cache).at_least(:once).with("nil")
expect(vivid.unlink!("nil")).to eql(nil)
expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ] })
end
it "should raise an exception if it traverses a nil" do
- with_breadcrumb("nil")
expect(root).not_to receive(:reset_cache)
expect { vivid.unlink!("nil", "foo") }.to raise_error(Chef::Exceptions::NoSuchAttribute)
expect(vivid).to eql({ "one" => { "two" => { "three" => "four" } }, "array" => [ 0, 1, 2 ], "nil" => nil })
end
end
end
+
+describe Chef::Node::AttrArray do
+ let(:root) { instance_double(Chef::Node::Attribute) }
+
+ let(:array) do
+ Chef::Node::AttrArray.new(
+ %w{zero one two},
+ root
+ )
+ end
+
+ context "#<<" do
+ it "converts a Hash appended with #<< to a VividMash" do
+ array << { "three" => "four" }
+ expect(array[3].class).to eql(Chef::Node::VividMash)
+ end
+
+ it "deeply converts objects appended with #<<" do
+ array << [ { "three" => [ 0, 1] } ]
+ expect(array[3].class).to eql(Chef::Node::AttrArray)
+ expect(array[3][0].class).to eql(Chef::Node::VividMash)
+ expect(array[3][0]["three"].class).to eql(Chef::Node::AttrArray)
+ end
+ end
+
+ context "#[]=" do
+ it "assigning a Hash into an array converts it to VividMash" do
+ array[0] = { "zero" => "zero2" }
+ expect(array[0].class).to eql(Chef::Node::VividMash)
+ end
+ end
+
+ context "#push" do
+ it "pushing a Hash into an array converts it to VividMash" do
+ array.push({ "three" => "four" })
+ expect(array[3].class).to eql(Chef::Node::VividMash)
+ end
+ end
+
+ context "#unshift" do
+ it "unshifting a Hash into an array converts it to VividMash" do
+ array.unshift({ "zero" => "zero2" })
+ expect(array[0].class).to eql(Chef::Node::VividMash)
+ end
+ end
+
+ context "#insert" do
+ it "inserting a Hash into an array converts it to VividMash" do
+ array.insert(1, { "zero" => "zero2" })
+ expect(array[1].class).to eql(Chef::Node::VividMash)
+ end
+ end
+
+ context "#collect!" do
+ it "converts Hashes" do
+ array.collect! { |x| { "zero" => "zero2" } }
+ expect(array[1].class).to eql(Chef::Node::VividMash)
+ end
+ end
+
+ context "#map!" do
+ it "converts Hashes" do
+ array.map! { |x| { "zero" => "zero2" } }
+ expect(array[1].class).to eql(Chef::Node::VividMash)
+ end
+ end
+
+ context "#compact!" do
+ it "VividMashes remain VividMashes" do
+ array = Chef::Node::AttrArray.new(
+ [ nil, { "one" => "two" }, nil ],
+ root
+ )
+ expect(array[1].class).to eql(Chef::Node::VividMash)
+ array.compact!
+ expect(array[0].class).to eql(Chef::Node::VividMash)
+ end
+ end
+
+ context "#fill" do
+ it "inserts VividMashes for Hashes" do
+ array.fill({ "one" => "two" })
+ expect(array[0].class).to eql(Chef::Node::VividMash)
+ end
+ end
+
+ context "#flatten!" do
+ it "flattens sub-arrays maintaining VividMashes in them" do
+ array = Chef::Node::AttrArray.new(
+ [ [ { "one" => "two" } ], [ { "one" => "two" } ] ],
+ root
+ )
+ expect(array[0][0].class).to eql(Chef::Node::VividMash)
+ array.flatten!
+ expect(array[0].class).to eql(Chef::Node::VividMash)
+ end
+ end
+
+ context "#replace" do
+ it "replaces the array converting hashes to mashes" do
+ array.replace([ { "foo" => "bar" } ])
+ expect(array[0].class).to eql(Chef::Node::VividMash)
+ end
+ end
+end