require 'rspec_ext'
require "#{__FILE__.dirname}/helper"

describe "AbstractController" do  
  with_environment :test
  with_abstract_controller_spec
  
  before :all do
    @dir = "#{File.expand_path(File.dirname(__FILE__))}/abstract_controller_spec"    
    $LOAD_PATH << @dir    
    
    AbstractController = Crystal::AbstractController
  end
  
  after :all do
    $LOAD_PATH.delete @dir
    remove_constants %w(
      WorkspaceVariablesSpec
      SpecialResultSpec
      RespondToSpec
      ViewVariablesSpec
      OperationsOrderSpec
      NoTemplateSpec
      AbstractController
    )
  end
  
  it "should set workspace variables" do
    class ::WorkspaceVariablesSpec
      inherit AbstractController
  
      def action; end    
    end
  
    workspace = ccall WorkspaceVariablesSpec, 'action'    
  
    workspace.delete(:controller).should be_a(WorkspaceVariablesSpec)
    expected_result = {      
      :params => {},
  
      :class => WorkspaceVariablesSpec,   
      :method_name => "action", 
      :action => 'action',
  
      :content => ""
    }
    workspace.to_h(true).symbolize_keys.subset(expected_result.keys).should == expected_result
  end
    
  it "should be able to throw :special_result in controller or view and that result must be assigned as result" do
      class ::SpecialResultSpec
        inherit AbstractController    
        def action
          throw :special_result, "some content"
        end      
      end
      
      ccall(SpecialResultSpec, :action).content.should == "some content"
    end
      
    it "respond_to" do
      class ::RespondToSpec
        inherit AbstractController
        
        def action
          respond_to do |format|
            format.html{render :inline => 'html'}
            format.json{render :json => {:a => 'b'}}
          end
        end
      end
      
      ccall(RespondToSpec, :action, :format => 'html').content.should == 'html'
      ccall(RespondToSpec, :action, :format => 'json').content.should == %({"a":"b"})
      lambda{ccall(RespondToSpec, :action, :format => 'js')}.should raise_error(/Can't respond to js format/)
    end
    
    it "controller's instance variables must be available in view, and also other variables" do
      class ::ViewVariablesSpec
        inherit AbstractController
        
        def action
          @instance_variable = "iv value"
        end
      end
      
      ccall(
        ViewVariablesSpec, :action, 
        :param => 'param value', :format => Crystal::Format.new('html')
      ).content.should == %(\
controller: ViewVariablesSpec

class: ViewVariablesSpec
method_name: action
action: action

instance_variable: iv value

params: param value
format: html)
    end
    
    it "operations order" do
      class ::OperationsOrderSpec
        inherit AbstractController
        
        def self.result
          @result ||= []
        end
        
        around do |controller, block|
          begin
            OperationsOrderSpec.result << :before
            block.call
          ensure
            OperationsOrderSpec.result << :after
          end
        end
        
        def action
          OperationsOrderSpec.result << :action
        end
      end
      
      ccall(OperationsOrderSpec, :action)
      OperationsOrderSpec.result.should == [:before, :action, :template, :after]    
    end
    
    it "should write empty response if no template for action" do
      class NoTemplateSpec
        inherit AbstractController
        
        def action; end
      end
      
      ccall(NoTemplateSpec, :action).content.should == ""
    end
end