require "#{File.expand_path(File.dirname(__FILE__))}/helper"

describe "Controller render" do
  with_environment :test
  with_abstract_controller_spec
  
  before :all do
    @dir = "#{File.expand_path(File.dirname(__FILE__))}/controller_render_spec"    
    $LOAD_PATH << @dir    
    AbstractController = Crystal::AbstractController
  end
  
  after :all do
    $LOAD_PATH.delete @dir
    remove_constants %w(
      LayoutFiltersSpec
      LayoutSpec
      AnotherLayout
      ExplicitRenderSpec
      RenderInsideOfControllerSpec
      ForbidPartialAsActionSpec
      FormatSpec
      AlreadyRenderedSpec
      SpecialFormatSpec
      AnotherActionSpec
      InlineRenderSpec
      AbstractController
    )
  end
    
  describe 'layout' do  
    it "should use :except and :only in layout" do
      class ::LayoutFiltersSpec
        inherit AbstractController
        layout '/layouts/app', :only => :action_with_layout
        
        def action_with_layout; end
        def action_without_layout; end
      end
      
      ccall(LayoutFiltersSpec, :action_with_layout).content.should == "Layout html, content"  
      ccall(LayoutFiltersSpec, :action_without_layout).content.should == "content"
    end
    
    it "should apply formats to layout" do
      class LayoutSpec
        inherit AbstractController
        layout '/layouts/app'
      
        def action; end      
      end
    
      ccall(LayoutSpec, :action, :format => :html).content.should == "Layout html, content"  
      ccall(LayoutSpec, :action, :format => :js).content.should == "Layout js, content"
    end  
      
    it "should take :layout => false or :layout => '/another_layout'" do
      class AnotherLayout
        inherit AbstractController
        layout '/layout/app'
        
        def action; end
        
        def without_layout
          render :action => 'action', :layout => false
        end
        
        def another_layout
          render :action => 'action', :layout => '/layouts/admin'
        end        
      end
      
      ccall(AnotherLayout, :without_layout).content.should == "action"
      ccall(AnotherLayout, :another_layout).content.should == "Admin layout, action"
    end
      
    
    it "explicitly rendered action shold be rendered with layout but template without" do
      class ::ExplicitRenderSpec
        inherit AbstractController
        layout '/layouts/app'
        
        def another_action; end
        
        def action          
          render :action => 'another_action'
        end
        
        def render_template
          render '/some_template'
        end
      end
      
      ccall(ExplicitRenderSpec, :action).content.should == "Layout html, another action"
      ccall(ExplicitRenderSpec, :render_template).content.should == "some template"
    end    
  end
  
  it "inside of controller" do
    class ::RenderInsideOfControllerSpec
      inherit AbstractController

      def some_action
        render '/some_template'
      end    
    end

    ccall(RenderInsideOfControllerSpec, 'some_action').content.should == "some template"
  end
  
  it "should not allow to render partials as actions" do
    class ::ForbidPartialAsActionSpec
      inherit AbstractController
      def action; end
    end

    lambda{ccall ForbidPartialAsActionSpec, :action}.should raise_error(/No template/)
  end
  
  it "should render view with right format" do
    class FormatSpec
      inherit AbstractController
      def action; end
    end

    ccall(FormatSpec, :action, :format => :html).content.should == "html format"    
    ccall(FormatSpec, :action, :format => :js).content.should == "js format"
  end
  
  it "should be able to use Template.render for different purposes (mail for example)" do
    Crystal::Template.render("/standalone", :locals => {:a => 'a'}).should == 'standalone usage, a'
  end
  
  it "should not rener if already rendered in controller" do
    class ::AlreadyRenderedSpec
      inherit AbstractController

      def action
        render '/AlreadyRenderedSpec/custom_template'
      end
    end

    ccall(AlreadyRenderedSpec, :action).content.should == 'custom content'
  end
  
  it "should handle serialization :json => obj (:xml, :js)" do
    class ::SpecialFormatSpec
      inherit AbstractController
      
      def json_action
        render :json => {:a => "b"}
      end
      
      def xml_action
        render :xml => {:a => "b"}
      end
    end
    
    ccall(SpecialFormatSpec, :json_action, :format => :json).content.should == %({"a":"b"})      
    ccall(SpecialFormatSpec, :xml_action, :format => :xml).content.should =~ /<a>b<\/a>/      
    lambda{
      ccall(SpecialFormatSpec, :json_action, :format => :xml)
    }.should raise_error(/responing with :json to the :xml/)
  end
  
  it "should render another action via :action => :action_name" do
    class ::AnotherActionSpec
      inherit AbstractController
  
      def another_action; end
      
      def action          
        render :action => 'another_action'
      end
    end
    
    ccall(AnotherActionSpec, :action).content.should == "another action"
  end
    
  it "should take :inline => 'hi' option" do
    class ::InlineRenderSpec
      inherit AbstractController
      
      def action
        render :inline => "content"
      end
    end
    
    ccall(InlineRenderSpec, :action).content.should == "content"
  end
end