diff options
Diffstat (limited to 'spec/unit/node_spec.rb')
-rw-r--r-- | spec/unit/node_spec.rb | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/spec/unit/node_spec.rb b/spec/unit/node_spec.rb index a78ad2c076..3b9501d73c 100644 --- a/spec/unit/node_spec.rb +++ b/spec/unit/node_spec.rb @@ -1709,4 +1709,88 @@ describe Chef::Node do end end + describe "path tracking via __path" do + it "works through hash keys" do + node.default["foo"] = { "bar" => { "baz" => "qux" } } + expect(node["foo"]["bar"].__path).to eql(%w{foo bar}) + end + + it "works through the default level" do + node.default["foo"] = { "bar" => { "baz" => "qux" } } + expect(node.default["foo"]["bar"].__path).to eql(%w{foo bar}) + end + + it "works through arrays" do + node.default["foo"] = [ { "bar" => { "baz" => "qux" } } ] + expect(node["foo"][0].__path).to eql(["foo", 0]) + expect(node["foo"][0]["bar"].__path).to eql(["foo", 0, "bar"]) + end + + it "works through arrays at the default level" do + node.default["foo"] = [ { "bar" => { "baz" => "qux" } } ] + expect(node.default["foo"][0].__path).to eql(["foo", 0]) + expect(node.default["foo"][0]["bar"].__path).to eql(["foo", 0, "bar"]) + end + + # if we set __path in the initializer we'd get this wrong, this is why we + # update the path on every #[] or #[]= operator + it "works on access when the node has been rearranged" do + node.default["foo"] = { "bar" => { "baz" => "qux" } } + a = node.default["foo"] + node.default["fizz"] = a + expect(node["fizz"]["bar"].__path).to eql(%w{fizz bar}) + expect(node["foo"]["bar"].__path).to eql(%w{foo bar}) + end + + # We have a problem because the __path is stored on in each node, but the + # node can be wired up at multiple locations in the tree via pointers. One + # solution would be to deep-dup the value in `#[]=(key, value)` and fix the + # __path on all the dup'd nodes. The problem is that this would create an + # unusual situation where after assignment, you couldn't mutate the thing you + # hand a handle on. I'm not entirely positive this behavior is the correct + # thing to support, but it is more hash-like (although if we start with a hash + # then convert_value does its thing and we *do* get dup'd on assignment). This + # behavior likely makes any implementation of a deep merge cache built over the + # top of __path tracking have edge conditions where it will fail. + # + # Removing this support would be a breaking change. The test is included here + # because it seems most likely that someone would break this behavior while trying + # to fix __path behavior. + it "does not dup in the background when a node is assigned" do + # get a handle on a vividmash (can't be a hash or else we convert_value it) + node.default["foo"] = { "bar" => { "baz" => "qux" } } + a = node.default["foo"] + # assign that somewhere else in the tree + node.default["fizz"] = a + # now upate the source + a["duptest"] = true + # the tree should have been updated + expect(node.default["fizz"]["duptest"]).to be true + expect(node["fizz"]["duptest"]).to be true + end + end + + describe "root tracking via __root" do + it "works through hash keys" do + node.default["foo"] = { "bar" => { "baz" => "qux" } } + expect(node["foo"]["bar"].__root).to eql(node.attributes) + end + + it "works through the default level" do + node.default["foo"] = { "bar" => { "baz" => "qux" } } + expect(node.default["foo"]["bar"].__root).to eql(node.attributes) + end + + it "works through arrays" do + node.default["foo"] = [ { "bar" => { "baz" => "qux" } } ] + expect(node["foo"][0].__root).to eql(node.attributes) + expect(node["foo"][0]["bar"].__root).to eql(node.attributes) + end + + it "works through arrays at the default level" do + node.default["foo"] = [ { "bar" => { "baz" => "qux" } } ] + expect(node.default["foo"][0].__root).to eql(node.attributes) + expect(node.default["foo"][0]["bar"].__root).to eql(node.attributes) + end + end end |