require "helper"
require "thor/actions"

describe Thor::Actions::EmptyDirectory do
  before do
    ::FileUtils.rm_rf(destination_root)
  end

  def empty_directory(destination, options = {})
    @action = Thor::Actions::EmptyDirectory.new(base, destination)
  end

  def invoke!
    capture(:stdout) { @action.invoke! }
  end

  def revoke!
    capture(:stdout) { @action.revoke! }
  end

  def base
    @base ||= MyCounter.new([1, 2], {}, destination_root: destination_root)
  end

  describe "#destination" do
    it "returns the full destination with the destination_root" do
      expect(empty_directory("doc").destination).to eq(File.join(destination_root, "doc"))
    end

    it "takes relative root into account" do
      base.inside("doc") do
        expect(empty_directory("contents").destination).to eq(File.join(destination_root, "doc", "contents"))
      end
    end
  end

  describe "#relative_destination" do
    it "returns the relative destination to the original destination root" do
      base.inside("doc") do
        expect(empty_directory("contents").relative_destination).to eq("doc/contents")
      end
    end
  end

  describe "#given_destination" do
    it "returns the destination supplied by the user" do
      base.inside("doc") do
        expect(empty_directory("contents").given_destination).to eq("contents")
      end
    end
  end

  describe "#invoke!" do
    it "copies the file to the specified destination" do
      empty_directory("doc")
      invoke!
      expect(File.exist?(File.join(destination_root, "doc"))).to be true
    end

    it "shows created status to the user" do
      empty_directory("doc")
      expect(invoke!).to eq("      create  doc\n")
    end

    it "does not create a directory if pretending" do
      base.inside("foo", pretend: true) do
        empty_directory("ghost")
      end
      expect(File.exist?(File.join(base.destination_root, "ghost"))).to be false
    end

    describe "when directory exists" do
      it "shows exist status" do
        empty_directory("doc")
        invoke!
        expect(invoke!).to eq("       exist  doc\n")
      end
    end
  end

  describe "#revoke!" do
    it "removes the destination file" do
      empty_directory("doc")
      invoke!
      revoke!
      expect(File.exist?(@action.destination)).to be false
    end
  end

  describe "#exists?" do
    it "returns true if the destination file exists" do
      empty_directory("doc")
      expect(@action.exists?).to be false
      invoke!
      expect(@action.exists?).to be true
    end
  end

  context "protected methods" do
    describe "#convert_encoded_instructions" do
      before do
        empty_directory("test_dir")
        allow(@action.base).to receive(:file_name).and_return("expected")
      end

      it "accepts and executes a 'legal' %\w+% encoded instruction" do
        expect(@action.send(:convert_encoded_instructions, "%file_name%.txt")).to eq("expected.txt")
      end

      it "accepts and executes a private %\w+% encoded instruction" do
        @action.base.extend Module.new {
          def private_file_name
            "expected"
          end
          private :private_file_name
        }
        expect(@action.send(:convert_encoded_instructions, "%private_file_name%.txt")).to eq("expected.txt")
      end

      it "ignores an 'illegal' %\w+% encoded instruction" do
        expect(@action.send(:convert_encoded_instructions, "%some_name%.txt")).to eq("%some_name%.txt")
      end

      it "ignores incorrectly encoded instruction" do
        expect(@action.send(:convert_encoded_instructions, "%some.name%.txt")).to eq("%some.name%.txt")
      end
    end
  end
end
