#
# Author:: John Keiser (<jkeiser@chef.io>)
# Copyright:: Copyright 2013-2016, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

require "support/shared/integration/integration_helper"
require "support/shared/context/config"
require "chef/knife/list"
require "chef/knife/show"

describe "chef_repo_path tests", :workstation do
  include IntegrationSupport
  include KnifeSupport

  let(:error_rel_path_outside_repo) { /^ERROR: Attempt to use relative path '' when current directory is outside the repository path/ }

  # TODO alternate repo_path / *_path
  context "alternate *_path" do
    when_the_repository "has clients and clients2, cookbooks and cookbooks2, etc." do
      before do
        file "clients/client1.json", {}
        file "cookbooks/cookbook1/metadata.rb", ""
        file "data_bags/bag/item.json", {}
        file "environments/env1.json", {}
        file "nodes/node1.json", {}
        file "roles/role1.json", {}
        file "users/user1.json", {}

        file "clients2/client2.json", {}
        file "cookbooks2/cookbook2/metadata.rb", ""
        file "data_bags2/bag2/item2.json", {}
        file "environments2/env2.json", {}
        file "nodes2/node2.json", {}
        file "roles2/role2.json", {}
        file "users2/user2.json", {}

        directory "chef_repo2" do
          file "clients/client3.json", {}
          file "cookbooks/cookbook3/metadata.rb", "name 'cookbook3'"
          file "data_bags/bag3/item3.json", {}
          file "environments/env3.json", {}
          file "nodes/node3.json", {}
          file "roles/role3.json", {}
          file "users/user3.json", {}
        end
      end

      it "knife list --local -Rfp --chef-repo-path chef_repo2 / grabs chef_repo2 stuff" do
        Chef::Config.delete(:chef_repo_path)
        knife("list --local -Rfp --chef-repo-path #{path_to("chef_repo2")} /").should_succeed <<~EOM
          /clients/
          /clients/client3.json
          /cookbooks/
          /cookbooks/cookbook3/
          /cookbooks/cookbook3/metadata.rb
          /data_bags/
          /data_bags/bag3/
          /data_bags/bag3/item3.json
          /environments/
          /environments/env3.json
          /nodes/
          /nodes/node3.json
          /roles/
          /roles/role3.json
          /users/
          /users/user3.json
        EOM
      end

      # "Skipping for BK... As Windows 2019 has 8dot3name disabled by default"
      it "knife list --local -Rfp --chef-repo-path chef_r~1 / grabs chef_repo2 stuff", :windows_only, :skip_buildkite do
        Chef::Config.delete(:chef_repo_path)
        knife("list --local -Rfp --chef-repo-path #{path_to("chef_r~1")} /").should_succeed <<~EOM
          /clients/
          /clients/client3.json
          /cookbooks/
          /cookbooks/cookbook3/
          /cookbooks/cookbook3/metadata.rb
          /data_bags/
          /data_bags/bag3/
          /data_bags/bag3/item3.json
          /environments/
          /environments/env3.json
          /nodes/
          /nodes/node3.json
          /roles/
          /roles/role3.json
          /users/
          /users/user3.json
        EOM
      end

      # "Skipping for BK... As Windows 2019 has 8dot3name disabled by default"
      it "knife list --local -Rfp --chef-repo-path chef_r~1 / grabs chef_repo2 stuff", :windows_only, :skip_buildkite do
        Chef::Config.delete(:chef_repo_path)
        knife("list -z -Rfp --chef-repo-path #{path_to("chef_r~1")} /").should_succeed <<~EOM
          /acls/
          /acls/clients/
          /acls/clients/client3.json
          /acls/containers/
          /acls/cookbook_artifacts/
          /acls/cookbooks/
          /acls/cookbooks/cookbook3.json
          /acls/data_bags/
          /acls/data_bags/bag3.json
          /acls/environments/
          /acls/environments/env3.json
          /acls/groups/
          /acls/nodes/
          /acls/nodes/node3.json
          /acls/organization.json
          /acls/policies/
          /acls/policy_groups/
          /acls/roles/
          /acls/roles/role3.json
          /clients/
          /clients/client3.json
          /containers/
          /cookbook_artifacts/
          /cookbooks/
          /cookbooks/cookbook3/
          /cookbooks/cookbook3/metadata.rb
          /data_bags/
          /data_bags/bag3/
          /data_bags/bag3/item3.json
          /environments/
          /environments/env3.json
          /groups/
          /invitations.json
          /members.json
          /nodes/
          /nodes/node3.json
          /org.json
          /policies/
          /policy_groups/
          /roles/
          /roles/role3.json
        EOM
      end

      context "when all _paths are set to alternates" do
        before :each do
          %w{client cookbook data_bag environment node role user}.each do |object_name|
            Chef::Config["#{object_name}_path".to_sym] = File.join(Chef::Config.chef_repo_path, "#{object_name}s2")
          end
          Chef::Config.chef_repo_path = File.join(Chef::Config.chef_repo_path, "chef_repo2")
        end

        it "knife list --local -Rfp --chef-repo-path chef_repo2 / grabs chef_repo2 stuff" do
          knife("list --local -Rfp --chef-repo-path #{path_to("chef_repo2")} /").should_succeed <<~EOM
            /clients/
            /clients/client3.json
            /cookbooks/
            /cookbooks/cookbook3/
            /cookbooks/cookbook3/metadata.rb
            /data_bags/
            /data_bags/bag3/
            /data_bags/bag3/item3.json
            /environments/
            /environments/env3.json
            /nodes/
            /nodes/node3.json
            /roles/
            /roles/role3.json
            /users/
            /users/user3.json
          EOM
        end

        context "when cwd is at the top level" do
          before { cwd "." }
          it "knife list --local -Rfp fails" do
            knife("list --local -Rfp").should_fail(error_rel_path_outside_repo)
          end
        end

        context "when cwd is inside the data_bags directory" do
          before { cwd "data_bags" }
          it "knife list --local -Rfp fails" do
            knife("list --local -Rfp").should_fail(error_rel_path_outside_repo)
          end
        end

        context "when cwd is inside chef_repo2" do
          before { cwd "chef_repo2" }
          it "knife list --local -Rfp lists everything" do
            knife("list --local -Rfp").should_succeed <<~EOM
              clients/
              clients/client2.json
              cookbooks/
              cookbooks/cookbook2/
              cookbooks/cookbook2/metadata.rb
              data_bags/
              data_bags/bag2/
              data_bags/bag2/item2.json
              environments/
              environments/env2.json
              nodes/
              nodes/node2.json
              roles/
              roles/role2.json
              users/
              users/user2.json
            EOM
          end
        end

        context "when cwd is inside data_bags2" do
          before { cwd "data_bags2" }
          it "knife list --local -Rfp lists data bags" do
            knife("list --local -Rfp").should_succeed <<~EOM
              bag2/
              bag2/item2.json
            EOM
          end
          it "knife list --local -Rfp ../roles lists roles" do
            knife("list --local -Rfp ../roles").should_succeed "/roles/role2.json\n"
          end
        end
      end

      context "when all _paths except chef_repo_path are set to alternates" do
        before :each do
          %w{client cookbook data_bag environment node role user}.each do |object_name|
            Chef::Config["#{object_name}_path".to_sym] = File.join(Chef::Config.chef_repo_path, "#{object_name}s2")
          end
        end

        context "when cwd is at the top level" do
          before { cwd "." }
          it "knife list --local -Rfp lists everything" do
            knife("list --local -Rfp").should_succeed <<~EOM
              clients/
              clients/client2.json
              cookbooks/
              cookbooks/cookbook2/
              cookbooks/cookbook2/metadata.rb
              data_bags/
              data_bags/bag2/
              data_bags/bag2/item2.json
              environments/
              environments/env2.json
              nodes/
              nodes/node2.json
              roles/
              roles/role2.json
              users/
              users/user2.json
            EOM
          end
        end

        context "when cwd is inside the data_bags directory" do
          before { cwd "data_bags" }
          it "knife list --local -Rfp fails" do
            knife("list --local -Rfp").should_fail(error_rel_path_outside_repo)
          end
        end

        context "when cwd is inside chef_repo2" do
          before { cwd "chef_repo2" }
          it "knife list -Rfp fails" do
            knife("list --local -Rfp").should_fail(error_rel_path_outside_repo)
          end
        end

        context "when cwd is inside data_bags2" do
          before { cwd "data_bags2" }
          it "knife list --local -Rfp lists data bags" do
            knife("list --local -Rfp").should_succeed <<~EOM
              bag2/
              bag2/item2.json
            EOM
          end
        end
      end

      context "when only chef_repo_path is set to its alternate" do
        before :each do
          %w{client cookbook data_bag environment node role user}.each do |object_name|
            Chef::Config.delete("#{object_name}_path".to_sym)
          end
          Chef::Config.chef_repo_path = File.join(Chef::Config.chef_repo_path, "chef_repo2")
        end

        context "when cwd is at the top level" do
          before { cwd "." }
          it "knife list --local -Rfp fails" do
            knife("list --local -Rfp").should_fail(error_rel_path_outside_repo)
          end
        end

        context "when cwd is inside the data_bags directory" do
          before { cwd "data_bags" }
          it "knife list --local -Rfp fails" do
            knife("list --local -Rfp").should_fail(error_rel_path_outside_repo)
          end
        end

        context "when cwd is inside chef_repo2" do
          before { cwd "chef_repo2" }
          it "knife list --local -Rfp lists everything" do
            knife("list --local -Rfp").should_succeed <<~EOM
              clients/
              clients/client3.json
              cookbooks/
              cookbooks/cookbook3/
              cookbooks/cookbook3/metadata.rb
              data_bags/
              data_bags/bag3/
              data_bags/bag3/item3.json
              environments/
              environments/env3.json
              nodes/
              nodes/node3.json
              roles/
              roles/role3.json
              users/
              users/user3.json
            EOM
          end
        end

        context "when cwd is inside chef_repo2/data_bags" do
          before { cwd "chef_repo2/data_bags" }
          it "knife list --local -Rfp lists data bags" do
            knife("list --local -Rfp").should_succeed <<~EOM
              bag3/
              bag3/item3.json
            EOM
          end
        end
      end

      context "when paths are set to point to both versions of each" do
        before :each do
          %w{client cookbook data_bag environment node role user}.each do |object_name|
            Chef::Config["#{object_name}_path".to_sym] = [
              File.join(Chef::Config.chef_repo_path, "#{object_name}s"),
              File.join(Chef::Config.chef_repo_path, "#{object_name}s2"),
            ]
          end
          Chef::Config.chef_repo_path = File.join(Chef::Config.chef_repo_path, "chef_repo2")
        end

        context "when there is a directory in clients1 and file in clients2 with the same name" do
          before do
            directory "clients/blah.json"
            file "clients2/blah.json", {}
          end
          it "knife show /clients/blah.json succeeds" do
            knife("show --local /clients/blah.json").should_succeed <<~EOM
              /clients/blah.json:
              {

              }
            EOM
          end
        end

        context "when there is a file in cookbooks1 and directory in cookbooks2 with the same name" do
          before do
            file "cookbooks/blah", ""
            file "cookbooks2/blah/metadata.rb", ""
          end
          it "knife list -Rfp cookbooks shows files in blah" do
            knife("list --local -Rfp /cookbooks").should_succeed <<~EOM
              /cookbooks/blah/
              /cookbooks/blah/metadata.rb
              /cookbooks/cookbook1/
              /cookbooks/cookbook1/metadata.rb
              /cookbooks/cookbook2/
              /cookbooks/cookbook2/metadata.rb
            EOM
          end
        end

        context "when there is an empty directory in cookbooks1 and a real cookbook in cookbooks2 with the same name" do
          before do
            directory "cookbooks/blah"
            file "cookbooks2/blah/metadata.rb", ""
          end
          it "knife list -Rfp cookbooks shows files in blah" do
            knife("list --local -Rfp /cookbooks").should_succeed(<<~EOM, stderr: "WARN: Cookbook 'blah' is empty or entirely chefignored at #{Chef::Config.cookbook_path[0]}/blah\n")
              /cookbooks/blah/
              /cookbooks/blah/metadata.rb
              /cookbooks/cookbook1/
              /cookbooks/cookbook1/metadata.rb
              /cookbooks/cookbook2/
              /cookbooks/cookbook2/metadata.rb
            EOM
          end
        end

        context "when there is a cookbook in cookbooks1 and a cookbook in cookbooks2 with the same name" do
          before do
            file "cookbooks/blah/metadata.json", {}
            file "cookbooks2/blah/metadata.rb", ""
          end
          it "knife list -Rfp cookbooks shows files in the first cookbook and not the second" do
            knife("list --local -Rfp /cookbooks").should_succeed(<<~EOM, stderr: "WARN: Child with name 'blah' found in multiple directories: #{Chef::Config.cookbook_path[0]}/blah and #{Chef::Config.cookbook_path[1]}/blah\n")
              /cookbooks/blah/
              /cookbooks/blah/metadata.json
              /cookbooks/cookbook1/
              /cookbooks/cookbook1/metadata.rb
              /cookbooks/cookbook2/
              /cookbooks/cookbook2/metadata.rb
            EOM
          end
        end

        context "when there is a file in data_bags1 and a directory in data_bags2 with the same name" do
          before do
            file "data_bags/blah", ""
            file "data_bags2/blah/item.json", ""
          end
          it "knife list -Rfp data_bags shows files in blah" do
            knife("list --local -Rfp /data_bags").should_succeed <<~EOM
              /data_bags/bag/
              /data_bags/bag/item.json
              /data_bags/bag2/
              /data_bags/bag2/item2.json
              /data_bags/blah/
              /data_bags/blah/item.json
            EOM
          end
        end

        context "when there is a data bag in data_bags1 and a data bag in data_bags2 with the same name" do
          before do
            file "data_bags/blah/item1.json", ""
            file "data_bags2/blah/item2.json", ""
          end
          it "knife list -Rfp data_bags shows only items in data_bags1" do
            knife("list --local -Rfp /data_bags").should_succeed(<<~EOM, stderr: "WARN: Child with name 'blah' found in multiple directories: #{Chef::Config.data_bag_path[0]}/blah and #{Chef::Config.data_bag_path[1]}/blah\n")
              /data_bags/bag/
              /data_bags/bag/item.json
              /data_bags/bag2/
              /data_bags/bag2/item2.json
              /data_bags/blah/
              /data_bags/blah/item1.json
            EOM
          end
        end

        context "when there is a directory in environments1 and file in environments2 with the same name" do
          before do
            directory "environments/blah.json"
            file "environments2/blah.json", {}
          end
          it "knife show /environments/blah.json succeeds" do
            knife("show --local /environments/blah.json").should_succeed <<~EOM
              /environments/blah.json:
              {

              }
            EOM
          end
        end

        context "when there is a directory in nodes1 and file in nodes2 with the same name" do
          before do
            directory "nodes/blah.json"
            file "nodes2/blah.json", {}
          end
          it "knife show /nodes/blah.json succeeds" do
            knife("show --local /nodes/blah.json").should_succeed <<~EOM
              /nodes/blah.json:
              {

              }
            EOM
          end
        end

        context "when there is a directory in roles1 and file in roles2 with the same name" do
          before do
            directory "roles/blah.json"
            file "roles2/blah.json", {}
          end
          it "knife show /roles/blah.json succeeds" do
            knife("show --local /roles/blah.json").should_succeed <<~EOM
              /roles/blah.json:
              {

              }
            EOM
          end
        end

        context "when there is a directory in users1 and file in users2 with the same name" do
          before do
            directory "users/blah.json"
            file "users2/blah.json", {}
          end
          it "knife show /users/blah.json succeeds" do
            knife("show --local /users/blah.json").should_succeed <<~EOM
              /users/blah.json:
              {

              }
            EOM
          end
        end

        context "when cwd is at the top level" do
          before { cwd "." }
          it "knife list --local -Rfp fails" do
            knife("list --local -Rfp").should_fail(error_rel_path_outside_repo)
          end
        end

        context "when cwd is inside the data_bags directory" do
          before { cwd "data_bags" }
          it "knife list --local -Rfp lists data bags" do
            knife("list --local -Rfp").should_succeed <<~EOM
              bag/
              bag/item.json
              bag2/
              bag2/item2.json
            EOM
          end
        end

        context "when cwd is inside chef_repo2" do
          before { cwd "chef_repo2" }
          it "knife list --local -Rfp lists everything" do
            knife("list --local -Rfp").should_succeed <<~EOM
              clients/
              clients/client1.json
              clients/client2.json
              cookbooks/
              cookbooks/cookbook1/
              cookbooks/cookbook1/metadata.rb
              cookbooks/cookbook2/
              cookbooks/cookbook2/metadata.rb
              data_bags/
              data_bags/bag/
              data_bags/bag/item.json
              data_bags/bag2/
              data_bags/bag2/item2.json
              environments/
              environments/env1.json
              environments/env2.json
              nodes/
              nodes/node1.json
              nodes/node2.json
              roles/
              roles/role1.json
              roles/role2.json
              users/
              users/user1.json
              users/user2.json
            EOM
          end
        end

        context "when cwd is inside data_bags2" do
          before { cwd "data_bags2" }
          it "knife list --local -Rfp lists data bags" do
            knife("list --local -Rfp").should_succeed <<~EOM
              bag/
              bag/item.json
              bag2/
              bag2/item2.json
            EOM
          end
        end
      end

      context "when when chef_repo_path is set to both places and no other _path is set" do
        before :each do
          %w{client cookbook data_bag environment node role user}.each do |object_name|
            Chef::Config.delete("#{object_name}_path".to_sym)
          end
          Chef::Config.chef_repo_path = [
            Chef::Config.chef_repo_path,
            File.join(Chef::Config.chef_repo_path, "chef_repo2"),
          ]
        end

        context "when cwd is at the top level" do
          before { cwd "." }
          it "knife list --local -Rfp lists everything" do
            knife("list --local -Rfp").should_succeed <<~EOM
              clients/
              clients/client1.json
              clients/client3.json
              cookbooks/
              cookbooks/cookbook1/
              cookbooks/cookbook1/metadata.rb
              cookbooks/cookbook3/
              cookbooks/cookbook3/metadata.rb
              data_bags/
              data_bags/bag/
              data_bags/bag/item.json
              data_bags/bag3/
              data_bags/bag3/item3.json
              environments/
              environments/env1.json
              environments/env3.json
              nodes/
              nodes/node1.json
              nodes/node3.json
              roles/
              roles/role1.json
              roles/role3.json
              users/
              users/user1.json
              users/user3.json
            EOM
          end
        end

        context "when cwd is inside the data_bags directory" do
          before { cwd "data_bags" }
          it "knife list --local -Rfp lists data bags" do
            knife("list --local -Rfp").should_succeed <<~EOM
              bag/
              bag/item.json
              bag3/
              bag3/item3.json
            EOM
          end
        end

        context "when cwd is inside chef_repo2" do
          before { cwd "chef_repo2" }
          it "knife list --local -Rfp lists everything" do
            knife("list --local -Rfp").should_succeed <<~EOM
              clients/
              clients/client1.json
              clients/client3.json
              cookbooks/
              cookbooks/cookbook1/
              cookbooks/cookbook1/metadata.rb
              cookbooks/cookbook3/
              cookbooks/cookbook3/metadata.rb
              data_bags/
              data_bags/bag/
              data_bags/bag/item.json
              data_bags/bag3/
              data_bags/bag3/item3.json
              environments/
              environments/env1.json
              environments/env3.json
              nodes/
              nodes/node1.json
              nodes/node3.json
              roles/
              roles/role1.json
              roles/role3.json
              users/
              users/user1.json
              users/user3.json
            EOM
          end
        end

        context "when cwd is inside chef_repo2/data_bags" do
          before { cwd "chef_repo2/data_bags" }
          it "knife list --local -Rfp lists data bags" do
            knife("list --local -Rfp").should_succeed <<~EOM
              bag/
              bag/item.json
              bag3/
              bag3/item3.json
            EOM
          end
        end
      end

      context "when cookbook_path is set and nothing else" do
        before :each do
          %w{client data_bag environment node role user}.each do |object_name|
            Chef::Config.delete("#{object_name}_path".to_sym)
          end
          Chef::Config.delete(:chef_repo_path)
          Chef::Config.cookbook_path = File.join(@repository_dir, "chef_repo2", "cookbooks")
        end

        context "when cwd is at the top level" do
          before { cwd "." }
          it "knife list --local -Rfp fails" do
            knife("list --local -Rfp").should_fail(error_rel_path_outside_repo)
          end
        end

        context "when cwd is inside the data_bags directory" do
          before { cwd "data_bags" }
          it "knife list --local -Rfp fails" do
            knife("list --local -Rfp").should_fail(error_rel_path_outside_repo)
          end
        end

        context "when cwd is inside chef_repo2" do
          before { cwd "chef_repo2" }
          it "knife list --local -Rfp lists everything" do
            knife("list --local -Rfp").should_succeed <<~EOM
              clients/
              clients/client3.json
              cookbooks/
              cookbooks/cookbook3/
              cookbooks/cookbook3/metadata.rb
              data_bags/
              data_bags/bag3/
              data_bags/bag3/item3.json
              environments/
              environments/env3.json
              nodes/
              nodes/node3.json
              roles/
              roles/role3.json
              users/
              users/user3.json
            EOM
          end
        end

        context "when cwd is inside chef_repo2/data_bags" do
          before { cwd "chef_repo2/data_bags" }
          it "knife list --local -Rfp lists data bags" do
            knife("list --local -Rfp").should_succeed <<~EOM
              bag3/
              bag3/item3.json
            EOM
          end
        end
      end

      context "when cookbook_path is set to multiple places and nothing else is set" do
        before :each do
          %w{client data_bag environment node role user}.each do |object_name|
            Chef::Config.delete("#{object_name}_path".to_sym)
          end
          Chef::Config.delete(:chef_repo_path)
          Chef::Config.cookbook_path = [
            File.join(@repository_dir, "cookbooks"),
            File.join(@repository_dir, "chef_repo2", "cookbooks"),
          ]
        end

        context "when cwd is at the top level" do
          before { cwd "." }
          it "knife list --local -Rfp lists everything" do
            knife("list --local -Rfp").should_succeed <<~EOM
              clients/
              clients/client1.json
              clients/client3.json
              cookbooks/
              cookbooks/cookbook1/
              cookbooks/cookbook1/metadata.rb
              cookbooks/cookbook3/
              cookbooks/cookbook3/metadata.rb
              data_bags/
              data_bags/bag/
              data_bags/bag/item.json
              data_bags/bag3/
              data_bags/bag3/item3.json
              environments/
              environments/env1.json
              environments/env3.json
              nodes/
              nodes/node1.json
              nodes/node3.json
              roles/
              roles/role1.json
              roles/role3.json
              users/
              users/user1.json
              users/user3.json
            EOM
          end
        end

        context "when cwd is inside the data_bags directory" do
          before { cwd "data_bags" }
          it "knife list --local -Rfp lists data bags" do
            knife("list --local -Rfp").should_succeed <<~EOM
              bag/
              bag/item.json
              bag3/
              bag3/item3.json
            EOM
          end
        end

        context "when cwd is inside chef_repo2" do
          before { cwd "chef_repo2" }
          it "knife list --local -Rfp lists everything" do
            knife("list --local -Rfp").should_succeed <<~EOM
              clients/
              clients/client1.json
              clients/client3.json
              cookbooks/
              cookbooks/cookbook1/
              cookbooks/cookbook1/metadata.rb
              cookbooks/cookbook3/
              cookbooks/cookbook3/metadata.rb
              data_bags/
              data_bags/bag/
              data_bags/bag/item.json
              data_bags/bag3/
              data_bags/bag3/item3.json
              environments/
              environments/env1.json
              environments/env3.json
              nodes/
              nodes/node1.json
              nodes/node3.json
              roles/
              roles/role1.json
              roles/role3.json
              users/
              users/user1.json
              users/user3.json
            EOM
          end
        end

        context "when cwd is inside chef_repo2/data_bags" do
          before { cwd "chef_repo2/data_bags" }
          it "knife list --local -Rfp lists data bags" do
            knife("list --local -Rfp").should_succeed <<~EOM
              bag/
              bag/item.json
              bag3/
              bag3/item3.json
            EOM
          end
        end
      end

      context "when data_bag_path and chef_repo_path are set, and nothing else" do
        before :each do
          %w{client cookbook environment node role user}.each do |object_name|
            Chef::Config.delete("#{object_name}_path".to_sym)
          end
          Chef::Config.data_bag_path = File.join(Chef::Config.chef_repo_path, "data_bags")
          Chef::Config.chef_repo_path = File.join(Chef::Config.chef_repo_path, "chef_repo2")
        end

        context "when cwd is at the top level" do
          before { cwd "." }
          it "knife list --local -Rfp fails" do
            knife("list --local -Rfp").should_fail(error_rel_path_outside_repo)
          end
        end

        context "when cwd is inside the data_bags directory" do
          before { cwd "data_bags" }
          it "knife list --local -Rfp lists data bags" do
            knife("list --local -Rfp").should_succeed <<~EOM
              bag/
              bag/item.json
            EOM
          end
        end

        context "when cwd is inside chef_repo2" do
          before { cwd "chef_repo2" }
          it "knife list --local -Rfp lists everything" do
            knife("list --local -Rfp").should_succeed <<~EOM
              clients/
              clients/client3.json
              cookbooks/
              cookbooks/cookbook3/
              cookbooks/cookbook3/metadata.rb
              data_bags/
              data_bags/bag/
              data_bags/bag/item.json
              environments/
              environments/env3.json
              nodes/
              nodes/node3.json
              roles/
              roles/role3.json
              users/
              users/user3.json
            EOM
          end
        end

        context "when cwd is inside chef_repo2/data_bags" do
          before { cwd "chef_repo2/data_bags" }
          it "knife list --local -Rfp fails" do
            knife("list --local -Rfp").should_fail(error_rel_path_outside_repo)
          end
        end
      end

      context "when data_bag_path is set and nothing else" do
        include_context "default config options"

        before :each do
          %w{client cookbook environment node role user}.each do |object_name|
            Chef::Config.delete("#{object_name}_path".to_sym)
          end
          Chef::Config.delete(:chef_repo_path)
          Chef::Config.data_bag_path = File.join(@repository_dir, "data_bags")
        end

        it "knife list --local -Rfp / lists data bags" do
          knife("list --local -Rfp /").should_succeed <<~EOM
            /data_bags/
            /data_bags/bag/
            /data_bags/bag/item.json
          EOM
        end

        it "knife list --local -Rfp /data_bags lists data bags" do
          knife("list --local -Rfp /data_bags").should_succeed <<~EOM
            /data_bags/bag/
            /data_bags/bag/item.json
          EOM
        end

        context "when cwd is inside the data_bags directory" do
          before { cwd "data_bags" }
          it "knife list --local -Rfp lists data bags" do
            knife("list --local -Rfp").should_succeed <<~EOM
              bag/
              bag/item.json
            EOM
          end
        end
      end
    end

    when_the_repository "is empty" do
      context "when the repository _paths point to places that do not exist" do
        before :each do
          %w{client cookbook data_bag environment node role user}.each do |object_name|
            Chef::Config["#{object_name}_path".to_sym] = File.join(Chef::Config.chef_repo_path, "nowhere", object_name)
          end
          Chef::Config.chef_repo_path = File.join(Chef::Config.chef_repo_path, "nowhere")
        end

        it "knife list --local -Rfp / fails" do
          knife("list --local -Rfp /").should_succeed ""
        end

        it "knife list --local -Rfp /data_bags fails" do
          knife("list --local -Rfp /data_bags").should_fail("ERROR: /data_bags: No such file or directory\n")
        end
      end
    end
  end
end
