require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')

describe AccountsController do

  # having this here removes interesting details from other examples
  # i'd probably try to inline it
  def mock_account(stubs={})
    stubs = {
      :save => true,
      :update_attributes => true,
      :destroy => true,
      :to_xml => ''
    }.merge(stubs)
    @mock_account ||= mock_model(Account, stubs)
  end

  describe "responding to GET /accounts" do

    # using TDD I would not write this example
    it "should succeed" do
      Account.stub!(:find)
      get :index
      response.should be_success
    end

    # using TDD I would not write this example
    it "should render the 'index' template" do
      Account.stub!(:find)
      get :index
      response.should render_template('index')
    end

    # using TDD I would not write this example
    # the simpliest code that makes the example pass is:
    #   def index
    #     Account.find(:all)
    #   end
    # Which clearly isn't what you want. The next example is
    # what you want, and it removes the need for this example.
    it "should find all accounts" do
      Account.should_receive(:find).with(:all)
      get :index
    end

    # i like it
    it "should assign the found accounts for the view" do
      Account.should_receive(:find).and_return([mock_account])
      get :index
      assigns[:accounts].should == [mock_account]
    end

  end

  describe "responding to GET /accounts.xml" do

    before(:each) do
      request.env["HTTP_ACCEPT"] = "application/xml" 
    end

    # using TDD I would not write this example
    it "should succeed" do
      Account.stub!(:find).and_return([])
      get :index
      response.should be_success
    end

    # same comment as the example undder GET /accounts
    it "should find all accounts" do
      Account.should_receive(:find).with(:all).and_return([])
      get :index
    end

    # i like it
    it "should render the found accounts as xml" do
      Account.should_receive(:find).and_return(accounts = mock("Array of Accounts"))
      accounts.should_receive(:to_xml).and_return("generated XML")
      get :index
      response.body.should == "generated XML" 
    end

  end

  describe "responding to GET /accounts/1" do

    # using TDD I would not write this example
    it "should succeed" do
      Account.stub!(:find)
      get :show, :id => "1" 
      response.should be_success
    end

    # using TDD I would not write this example
    it "should render the 'show' template" do
      Account.stub!(:find)
      get :show, :id => "1" 
      response.should render_template('show')
    end

    # same comment as:
    #  "responding to GET /accounts" it "should find all accounts"
    it "should find the requested account" do
      Account.should_receive(:find).with("37")
      get :show, :id => "37" 
    end

    # i like it
    it "should assign the found account for the view" do
      Account.should_receive(:find).and_return(mock_account)
      get :show, :id => "1" 
      assigns[:account].should equal(mock_account)
    end

  end

  describe "responding to GET /accounts/1.xml" do

    before(:each) do
      request.env["HTTP_ACCEPT"] = "application/xml" 
    end

    # using TDD I would not write this example
    it "should succeed" do
      Account.stub!(:find).and_return(mock_account)
      get :show, :id => "1" 
      response.should be_success
    end

    # using TDD I would not write this example
    it "should find the account requested" do
      Account.should_receive(:find).with("37").and_return(mock_account)
      get :show, :id => "37" 
    end

    # i like it
    it "should render the found account as xml" do
      Account.should_receive(:find).and_return(mock_account)
      mock_account.should_receive(:to_xml).and_return("generated XML")
      get :show, :id => "1" 
      response.body.should == "generated XML" 
    end

  end

  describe "responding to GET /accounts/new" do

    # using TDD I would not write this example
    it "should succeed" do
      get :new
      response.should be_success
    end

    # using TDD I would not write this example
    it "should render the 'new' template" do
      get :new
      response.should render_template('new')
    end

    # same comment as:
    #  "responding to GET /accounts" it "should find all accounts"
    it "should create a new account" do
      Account.should_receive(:new)
      get :new
    end

    # i like it
    it "should assign the new account for the view" do
      Account.should_receive(:new).and_return(mock_account)
      get :new
      assigns[:account].should equal(mock_account)
    end

  end

  describe "responding to GET /accounts/1/edit" do

    # using TDD I would not write this example
    it "should succeed" do
      Account.stub!(:find)
      get :edit, :id => "1" 
      response.should be_success
    end

    # using TDD I would not write this example
    it "should render the 'edit' template" do
      Account.stub!(:find)
      get :edit, :id => "1" 
      response.should render_template('edit')
    end

    # same comment as:
    #  "responding to GET /accounts" it "should find all accounts"
    it "should find the requested account" do
      Account.should_receive(:find).with("37")
      get :edit, :id => "37" 
    end

    # i like it
    it "should assign the found Account for the view" do
      Account.should_receive(:find).and_return(mock_account)
      get :edit, :id => "1" 
      assigns[:account].should equal(mock_account)
    end

  end

  describe "responding to POST /accounts" do

    describe "with successful save" do

      it "should create a new account" do
        Account.should_receive(:new).with({'these' => 'params'}).and_return(mock_account)
        post :create, :account => {:these => 'params'}
      end

      # what view? it redirects. :)
      it "should assign the created account for the view" do
        Account.stub!(:new).and_return(mock_account)
        post :create, :account => {}
        assigns(:account).should equal(mock_account)
      end

      it "should redirect to the created account" do
        Account.stub!(:new).and_return(mock_account)
        post :create, :account => {}
        response.should redirect_to(account_url(mock_account))
      end

    end

    describe "with failed save" do

      it "should create a new account" do
        Account.should_receive(:new).with({'these' => 'params'}).and_return(mock_account(:save => false))
        post :create, :account => {:these => 'params'}
      end

      it "should assign the invalid account for the view" do
        Account.stub!(:new).and_return(mock_account(:save => false))
        post :create, :account => {}
        assigns(:account).should equal(mock_account)
      end

      it "should re-render the 'new' template" do
        Account.stub!(:new).and_return(mock_account(:save => false))
        post :create, :account => {}
        response.should render_template('new')
      end

    end

  end

  describe "responding to PUT /accounts/1" do

    describe "with successful update" do

      it "should find the requested account" do
        Account.should_receive(:find).with("37").and_return(mock_account)
        put :update, :id => "37" 
      end

      it "should update the found account" do
        Account.stub!(:find).and_return(mock_account)
        mock_account.should_receive(:update_attributes).with({'these' => 'params'})
        put :update, :id => "1", :account => {:these => 'params'}
      end

      # what view? it redirects
      it "should assign the found account for the view" do
        Account.stub!(:find).and_return(mock_account)
        put :update, :id => "1" 
        assigns(:account).should equal(mock_account)
      end

      it "should redirect to the account" do
        Account.stub!(:find).and_return(mock_account)
        put :update, :id => "1" 
        response.should redirect_to(account_url(mock_account))
      end

    end

    describe "with failed update" do

      it "should find the requested account" do
        Account.should_receive(:find).with("37").and_return(mock_account(:update_attributes => false))
        put :update, :id => "37" 
      end

      it "should update the found account" do
        Account.stub!(:find).and_return(mock_account)
        mock_account.should_receive(:update_attributes).with({'these' => 'params'})
        put :update, :id => "1", :account => {:these => 'params'}
      end

      it "should assign the found account for the view" do
        Account.stub!(:find).and_return(mock_account(:update_attributes => false))
        put :update, :id => "1" 
        assigns(:account).should equal(mock_account)
      end

      it "should re-render the 'edit' template" do
        Account.stub!(:find).and_return(mock_account(:update_attributes => false))
        put :update, :id => "1" 
        response.should render_template('edit')
      end

    end

  end

  describe "responding to DELETE /accounts/1" do

    # i think i would just combine this with the next spec
    it "should find the account requested" do
      Account.should_receive(:find).with("37").and_return(mock_account)
      delete :destroy, :id => "37" 
    end

    it "should call destroy on the found account" do
      Account.stub!(:find).and_return(mock_account)
      mock_account.should_receive(:destroy)
      delete :destroy, :id => "1" 
    end

    it "should redirect to the accounts list" do
      Account.stub!(:find).and_return(mock_account)
      delete :destroy, :id => "1" 
      response.should redirect_to(accounts_url)
    end

  end

end