require 'spec_helper'
# This spec was generated by rspec-rails when you ran the scaffold generator.
# It demonstrates how one might use RSpec to specify the controller code that
# was generated by the Rails when you ran the scaffold generator.

describe AccountsController do

  include AuthHelper
  include ModelHelper
  fixtures :accounts, :roles, :accounts_roles

  def norm_account
    @norm_account ||= accounts(:clerk)
  end

  def login_non_admin
    login(norm_account)
  end

  def login_admin
    login(admin_account)
  end

  def valid_params
    {'name' => 'newacc', 'sca_name' => 'Juan Gomez', 'contact_info' => 'juan@test.com',
      'password' => 'secret', 'password_confirmation' => 'secret'}
  end

  def invalid_params
    {'name' => 'bad', 'password' => '',
     'password_confirmation' => 'xx'}
  end


  describe "GET index" do
    it "requires view_accounts" do 
      verify_needs_right(:view_accounts) do
        get :index
      end
    end

    it "assigns all accounts as @accounts" do
      login_with_rights(:view_accounts)
      Account.stub(:all) { [norm_account, admin_account] }
      get :index
      assigns(:accounts).should eq([norm_account, admin_account])
    end
  end

  describe "GET show" do
  
    it "requires authorization" do 
      verify_needs_authorization do 
        get :show, :id => '22'
      end
    end
    
    describe "when able to view accounts" do 
      before :each do 
        login_with_rights(:view_accounts)
      end
    
      it "assigns the requested account as @account" do
        get :show, :id => norm_account.id.to_s
        assigns(:account).should eq(norm_account)
      end
    
      it "returns 404 when id is invalid" do
        get :show, :id => 100000
        response.status.should == 404
      end
    end
    
    describe "otherwise" do
      before :each do 
        login(:herald)
      end
            
      it "requires view_accounts when not same account" do 
        verify_needs_right(:view_accounts) do
          get :show, :id => accounts(:senior).id.to_s
        end
      end
      
      it "can view ones own account" do
        get :show, :id => accounts(:herald).id.to_s
        response.should be_ok
      end
    end
  end

  describe "GET new" do
    it "assigns a new named account as @account" do
      get :new
      assigns(:account).should be_an_instance_of(NamedAccount)
      assigns(:account).should be_new
    end
  end

  describe "GET edit" do
    it "requires authentication" do
      verify_needs_authorization do
        get :edit, :id => 3
      end
    end

    describe "when has modifier rights" do
      before :each do 
        login_with_rights(:modify_other_accounts)
      end
            
      it "assigns the requested account as @account" do
        get :edit, :id => norm_account.id.to_s
        response.should be_ok
        assigns(:account).should eq(norm_account)
      end
    end
    
    describe "when normal" do
      before :each do
        @account = login_with_rights
      end
      
      it "works if the current account is the request account" do
        get :edit, :id => @account.id
        response.should be_ok
        assigns(:account).should eq(@account)
      end
      
      it "is forbidden otherwise" do
        get :edit, :id => accounts(:clerk).id
        response.should be_forbidden
      end
    end
  end

  describe "POST create" do

    describe "with valid params" do
      it "assigns a newly created account as @account" do
        post :create, :account => valid_params
        new_account = assigns(:account)
        new_account.name.should eq(valid_params['name'])
        new_account.should be_persisted
      end
      
      it "the new account has type NamedAccount" do
        post :create, :account => valid_params
        assigns(:account).should be_instance_of(NamedAccount)
      end

      it "redirects to the created account" do
        post :create, :account => valid_params
        new_account = assigns(:account)
        response.should redirect_to(account_url(new_account))
      end
      
      it "add the current event to this account if there is a current event" do
        e = Event.current_event
        unless e
          e = Event.new(:title => 'New Event', :is_current => true)
          e.save!
        end
        post :create, :account => valid_params
        assigns(:account).events.should eq([e])
      end
      
      it "has no roles" do
        post :create, :account => valid_params
        assigns(:account).roles.should be_empty
      end
    end

    describe "with invalid params" do
      it "assigns a newly created but unsaved account as @account" do
        post :create, :account => invalid_params
        assigns(:account).should be_new
        assigns(:account).name.should == invalid_params['name']
      end

      it "re-renders the 'new' template" do
        post :create, :account => invalid_params
        response.should render_template("new")
      end
    end
  end

  describe "PUT update" do
    
    it "requires authentication" do 
      verify_needs_authorization do
        put :update, :id => norm_account.id, :account => valid_params
      end
    end

    describe "when can modify other events" do
      before :each do
        @account = login_with_rights(:modify_other_accounts)
      end
  
      describe "with valid params" do
        def run_put
          put :update, :id => norm_account.id.to_s, :account => valid_params
        end
      
        it "updates the requested account" do
          run_put
          changed_account = Account.find(norm_account.id)
          Account.login(valid_params['name'], valid_params['password']).should eq(changed_account)
        end

        it "assigns the requested account as @account" do
          run_put
          assigns(:account).should eq(norm_account)
        end

        it "redirects to the account" do
          run_put
          response.should redirect_to(account_url(norm_account))
        end
      end

      describe "with invalid params" do
        def run_put
          put :update, :id => norm_account.id.to_s, :account => invalid_params
        end

        it "does not modify the account" do
          run_put
          saved_account = Account.find(norm_account.id)
          saved_account.name.should == norm_account.name
        end

        it "keeps the original account" do
          run_put
          assigns(:account).should eq(norm_account)
        end

        it "re-renders the 'edit' template" do
          puts "Starting to run put"
          run_put
          puts "End running put"
          response.should render_template("edit")
        end
      end
    end
    
    describe "when otherwise authenticated" do
      before :each do 
        login(:herald)
      end
      
      it "is forbidden to edit other accounts" do
        put :update, :id => accounts(:senior).id, :account => valid_params
        response.should be_forbidden
      end
      
      it "can update current account" do
        put :update, :id => accounts(:herald).id, :account => valid_params
        response.should be_redirect
      end
    end
  end
  
  describe "GET roles" do
    it "requires authentication" do 
      verify_needs_authorization do
        get :roles, :id => 1
      end
    end

    describe "when can edit account roles" do
      before :each do
        @account = login_with_rights(:edit_account_roles)
      end
      
      it "assigns @role_account to the specified account" do
        account = accounts(:herald)
        get :roles, :id => account.id.to_s
        assigns(:role_account).should eq(account)
      end
      
      it "assigns @roles to the current accounts roles" do
        @account.roles << roles(:clerk)
        @account.save!
        account = accounts(:senior)
        get :roles, :id => account.id.to_s
        assigns(:roles).should eq(@account.roles)
      end
      
      it "assigns all roles when it has add all account roles rights" do
        @account = login_with_rights(:edit_account_roles, :add_all_account_roles)
        get :roles, :id => accounts(:senior).id.to_s
        assigns(:roles).should eq(Role.all)
      end
    end
    
    describe "otherwise" do
      
      it "is forbidden" do
        verify_needs_right(:edit_account_roles) do
          get :roles, :id => 1
        end
      end
    end
  end
  
  describe "PUT roles" do
    def valid_params(id)
      role_syms = [:clerk, :senior, :herald]
      @roles = role_syms.map {|r| Role.find_by_name(r)}
      role_ids = Hash[@roles.map {|r| [r.id, 1]}]
      return {:roles => role_ids, :id => id}
    end
      
    it "requires authentication" do 
      verify_needs_authorization do
        get :roles, valid_params(1)
      end
    end

    describe "when can edit account roles" do
      before :each do
        @account = login_with_rights(:edit_account_roles)
      end
      
      def invalid_params
        return {:roles => [100, 2000], :id => 3}
      end
      
      describe "with valid params" do
        it "updates the roles of the account" do
          account = accounts(:herald)
          put :roles, valid_params(account.id)
          account.roles.should include(*@roles)
          account.roles.size.should eq(@roles.size)
        end
      
        it "redirects to accounts" do
          put :roles, valid_params(accounts(:senior).id)
          response.should redirect_to(:accounts)
        end
      end
      
      describe "with invalid params" do
        it "returns a 400" do
          put :roles, invalid_params
          response.status.should be(400)
        end
      end
    end
    
    describe "otherwise" do
      
      it "is forbidden" do
        verify_needs_right(:edit_account_roles) do
          put :roles, valid_params(1)
        end
      end
    end
  end

end