describe Commander do
  
	before :each do
    mock_terminal
	  create_test_command
	end
	
  describe "#program" do
    it "should set / get program information" do
      program :name, 'test'
  	  program(:name).should == 'test'
    end
    
    it "should allow arbitrary blocks of global help documentation" do
      program :help, 'Copyright', 'TJ Holowaychuk'
  	  program(:help)['Copyright'].should == 'TJ Holowaychuk'
    end
    
    it "should raise an error when required info has not been set" do
      new_command_runner '--help'
  	  program :name, ''
      lambda { run! }.should raise_error(Commander::Runner::CommandError)
    end
  end
  
  describe "#command" do
  	it "should return a command instance when only the name is passed" do
  	  command(:test).should be_instance_of(Commander::Command)
  	end
    
    it "should raise InvalidCommandError when the command does not exist" do
      lambda { command(:im_not_real) }.should raise_error(Commander::Runner::InvalidCommandError)
    end
  end
  
  describe "#alias_command" do
    it "should alias a command" do
      alias_command :foo, :test
      command(:foo).should == command(:test)
    end
    
    it "should pass arguments passed to the alias when called" do
      new_command_runner 'install', 'gem', 'commander' do
        command :install do |c|
          c.option '--gem-name NAME', 'Install a gem'
          c.when_called { |_, options| options.gem_name.should == 'commander' }
        end 
        alias_command :'install gem', :install, '--gem-name'
        command(:install).should_receive(:run).once
      end.run!
    end
  end
  
  describe "#global_option" do
    it "should be invoked when used in the args list" do
      file = ''
      new_command_runner 'test', '--config', 'foo' do
        global_option('--config FILE') { |f| file = f }
      end.run!
      file.should == 'foo'
    end
  end
  
  # describe "--trace" do
  #   it "should display pretty errors by default" do
  #     new_command_runner 'test' do
  #       raise 'cookies!'
  #     end.run!
  #     @output.should == 'error: cookies!. use --trace to view backtrace'
  #   end
  #   
  #   it "should display callstack when using this switch" do
  #     lambda { 
  #       new_command_runner 'test', '--trace' do
  #         raise 'cookies!'
  #       end.run!
  #     }.should raise_error
  #   end
  # end
  
  describe "--version" do
    it "should output program version" do
      run('--version').should == "test 1.2.3\n"
    end
  end
  
  describe "--help" do
    it "should not output an invalid command message" do
      run('--help').should_not == "invalid command. Use --help for more information\n"
    end
  end
  
  describe "with invalid options" do
    it "should output an invalid option message" do
      run('test', '--invalid-option').should == "invalid option: --invalid-option\n"
    end
  end
  
  describe "with invalid sub-command passed" do
    it "should output an invalid command message" do
      run('foo').should == "invalid command. Use --help for more information\n"
    end
  end
  
  describe "with invalid sub-command passed to help" do
    it "should output an invalid command message" do
      run('help', 'does_not_exist').should == "invalid command. Use --help for more information\n"
    end
  end
  
  describe "#valid_command_names_from" do
    it "should return array of valid command names" do
      command('foo bar') {}
   	  command('foo bar foo') {}
   	  command_runner.valid_command_names_from('foo', 'bar', 'foo').should == ['foo bar', 'foo bar foo']
    end
    
    it "should return empty array when no possible command names exist" do
   	  command_runner.valid_command_names_from('fake', 'command', 'name').should == []
    end
  end
  
  describe "#command_name_from_args" do
    it "should locate command within arbitrary arguments passed" do
   	  new_command_runner '--help', '--arbitrary', 'test'
   	  command_runner.command_name_from_args.should == 'test'
    end
    
    it "should support multi-word commands" do
   	  new_command_runner '--help', '--arbitrary', 'some', 'long', 'command', 'foo'
   	  command('some long command') {}
   	  command_runner.command_name_from_args.should == 'some long command'
    end
    
    it "should match the longest possible command" do
   	  new_command_runner '--help', '--arbitrary', 'foo', 'bar', 'foo'
   	  command('foo bar') {}
   	  command('foo bar foo') {}
   	  command_runner.command_name_from_args.should == 'foo bar foo'      
    end
    
    it "should use the left-most command name when multiple are present" do
   	  new_command_runner 'help', 'test'
   	  command_runner.command_name_from_args.should == 'help'      
    end
  end
  
  describe "#active_command" do
    it "should resolve the active command" do
      new_command_runner '--help', 'test'
      command_runner.active_command.should be_instance_of(Commander::Command)
    end
    
    it "should resolve active command when invalid options are passed" do
      new_command_runner '--help', 'test', '--arbitrary'
      command_runner.active_command.should be_instance_of(Commander::Command)
    end
    
    it "should raise invalid command error when the command is not found" do
      new_command_runner 'foo'
      lambda { command_runner.active_command }.should raise_error(Commander::Runner::InvalidCommandError)
    end
  end
  
  describe "#default_command" do
    it "should allow you to default any command when one is not explicitly passed" do
      new_command_runner '--trace' do
        default_command :test
        command(:test).should_receive(:run).once
        command_runner.active_command.should == command(:test)
      end.run!
    end
    
    it "should not prevent other commands from being called" do
      new_command_runner 'foo', 'bar', '--trace' do
        default_command :test
        command(:'foo bar'){}
        command(:'foo bar').should_receive(:run).once
        command_runner.active_command.should == command(:'foo bar')
      end.run!
    end
    
    it "should not prevent longer commands to use the same words as the default" do
      new_command_runner 'foo', 'bar', 'something'
      default_command :'foo bar'
      command(:'foo bar'){}
      command(:'foo bar something'){}
      command_runner.active_command.should == command(:'foo bar something')
    end
    
    it "should allow defaulting of command aliases" do
      new_command_runner '--trace' do
        default_command :foobar
        alias_command :foobar, :test
        command(:test).should_receive(:run).once
      end.run!
    end
  end
  
  describe "should function correctly" do
    it "when options are passed before the command name" do
      new_command_runner '--trace', 'test', 'foo', 'bar' do
        @command.when_called do |args, options|
          args.should == ['foo', 'bar']
          options.trace.should be_true
        end
      end.run!
    end

    it "when options are passed after the command name" do
      new_command_runner 'test', '--trace', 'foo', 'bar' do
        @command.when_called do |args, options|
          args.should == ['foo', 'bar']
          options.trace.should be_true
        end
      end.run!
    end

    it "when an argument passed is the same name as the command" do
      new_command_runner 'test', '--trace', 'foo', 'test', 'bar' do
        @command.when_called do |args, options|
          args.should == ['foo', 'test', 'bar']
          options.trace.should be_true
        end
      end.run!
    end
    
    it "when using multi-word commands" do
      new_command_runner '--trace', 'my', 'command', 'something', 'foo', 'bar' do
        command('my command') {}
        command_runner.command_name_from_args.should == 'my command'
        command_runner.args_without_command_name.should == ['--trace', 'something', 'foo', 'bar']
      end.run!
    end

    it "when using multi-word commands with parts of the command name as arguments" do
      new_command_runner '--trace', 'my', 'command', 'something', 'my', 'command' do
        command('my command') {}
        command_runner.command_name_from_args.should == 'my command'
        command_runner.args_without_command_name.should == ['--trace', 'something', 'my', 'command']
      end.run!
    end
    
    it "when using multi-word commands with other commands using the same words" do
      new_command_runner '--trace', 'my', 'command', 'something', 'my', 'command' do
        command('my command') {}
        command('my command something') {}
        command_runner.command_name_from_args.should == 'my command something'
        command_runner.args_without_command_name.should == ['--trace', 'my', 'command']
      end.run!
    end
  end
  
end