require 'helper'
require 'thor/actions'

describe Thor::Actions::InjectIntoFile do
  before do
    ::FileUtils.rm_rf(destination_root)
    ::FileUtils.cp_r(source_root, destination_root)
  end

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

  def revoker
    @revoker ||= MyCounter.new([1, 2], {}, :destination_root => destination_root, :behavior => :revoke)
  end

  def invoke!(*args, &block)
    capture(:stdout) { invoker.insert_into_file(*args, &block) }
  end

  def revoke!(*args, &block)
    capture(:stdout) { revoker.insert_into_file(*args, &block) }
  end

  def file
    File.join(destination_root, 'doc/README')
  end

  describe '#invoke!' do
    it 'changes the file adding content after the flag' do
      invoke! 'doc/README', "\nmore content", :after => '__start__'
      expect(File.read(file)).to eq("__start__\nmore content\nREADME\n__end__\n")
    end

    it 'changes the file adding content before the flag' do
      invoke! 'doc/README', "more content\n", :before => '__end__'
      expect(File.read(file)).to eq("__start__\nREADME\nmore content\n__end__\n")
    end

    it 'accepts data as a block' do
      invoke! 'doc/README', :before => '__end__' do
        "more content\n"
      end

      expect(File.read(file)).to eq("__start__\nREADME\nmore content\n__end__\n")
    end

    it 'logs status' do
      expect(invoke!('doc/README', "\nmore content", :after => '__start__')).to eq("      insert  doc/README\n")
    end

    it 'does not change the file if pretending' do
      invoker :pretend => true
      invoke! 'doc/README', "\nmore content", :after => '__start__'
      expect(File.read(file)).to eq("__start__\nREADME\n__end__\n")
    end

    it 'does not change the file if already includes content' do
      invoke! 'doc/README', :before => '__end__' do
        "more content\n"
      end

      expect(File.read(file)).to eq("__start__\nREADME\nmore content\n__end__\n")

      invoke! 'doc/README', :before => '__end__' do
        "more content\n"
      end

      expect(File.read(file)).to eq("__start__\nREADME\nmore content\n__end__\n")
    end

    it 'does change the file if already includes content and :force is true' do
      invoke! 'doc/README', :before => '__end__' do
        "more content\n"
      end

      expect(File.read(file)).to eq("__start__\nREADME\nmore content\n__end__\n")

      invoke! 'doc/README', :before => '__end__', :force => true do
        "more content\n"
      end

      expect(File.read(file)).to eq("__start__\nREADME\nmore content\nmore content\n__end__\n")
    end

  end

  describe '#revoke!' do
    it 'subtracts the destination file after injection' do
      invoke! 'doc/README', "\nmore content", :after => '__start__'
      revoke! 'doc/README', "\nmore content", :after => '__start__'
      expect(File.read(file)).to eq("__start__\nREADME\n__end__\n")
    end

    it 'subtracts the destination file before injection' do
      invoke! 'doc/README', "more content\n", :before => '__start__'
      revoke! 'doc/README', "more content\n", :before => '__start__'
      expect(File.read(file)).to eq("__start__\nREADME\n__end__\n")
    end

    it 'subtracts even with double after injection' do
      invoke! 'doc/README', "\nmore content", :after => '__start__'
      invoke! 'doc/README', "\nanother stuff", :after => '__start__'
      revoke! 'doc/README', "\nmore content", :after => '__start__'
      expect(File.read(file)).to eq("__start__\nanother stuff\nREADME\n__end__\n")
    end

    it 'subtracts even with double before injection' do
      invoke! 'doc/README', "more content\n", :before => '__start__'
      invoke! 'doc/README', "another stuff\n", :before => '__start__'
      revoke! 'doc/README', "more content\n", :before => '__start__'
      expect(File.read(file)).to eq("another stuff\n__start__\nREADME\n__end__\n")
    end

    it 'subtracts when prepending' do
      invoke! 'doc/README', "more content\n", :after => /\A/
      invoke! 'doc/README', "another stuff\n", :after => /\A/
      revoke! 'doc/README', "more content\n", :after => /\A/
      expect(File.read(file)).to eq("another stuff\n__start__\nREADME\n__end__\n")
    end

    it 'subtracts when appending' do
      invoke! 'doc/README', "more content\n", :before => /\z/
      invoke! 'doc/README', "another stuff\n", :before => /\z/
      revoke! 'doc/README', "more content\n", :before => /\z/
      expect(File.read(file)).to eq("__start__\nREADME\n__end__\nanother stuff\n")
    end

    it 'shows progress information to the user' do
      invoke!('doc/README', "\nmore content", :after => '__start__')
      expect(revoke!('doc/README', "\nmore content", :after => '__start__')).to eq("    subtract  doc/README\n")
    end
  end
end
