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

def valid_<%=rule_name%>_rule_data
  '["Rule Title", "Twitter Message to Find", "Other Plan", "1001"]'
end
  

describe RulesEngine::Rule::<%=rule_class%> do

  def valid_attributes
    {
      :<%=rule_name%>_title => 'Rule Title',
      :<%=rule_name%>_message => 'The Message',
      :<%=rule_name%>_plan => 'Next Plan'
    }
  end
  
  it "should be discoverable" do
    RulesEngine::Discovery.rule_class("RulesEngine::Rule::<%=rule_class%>").should == RulesEngine::Rule::<%=rule_class%>
  end

  describe "the expected class options" do    
    it "should be in the 'General' group" do
      RulesEngine::Rule::<%=rule_class%>.options[:group].should == "Twitter"
    end
    
    it "should have the diplay name of '<%=rule_class%> Rule'" do
      RulesEngine::Rule::<%=rule_class%>.options[:display_name].should == "Twitter Reader"
    end

    it "should have the help template of '/re_rule_definitions/<%=rule_name%>/help'" do
      RulesEngine::Rule::<%=rule_class%>.options[:help_partial].should == '/re_rule_definitions/<%=rule_name%>/help'
    end

    it "should have the new template of '/re_rule_definitions/<%=rule_name%>/new'" do
      RulesEngine::Rule::<%=rule_class%>.options[:new_partial].should == '/re_rule_definitions/<%=rule_name%>/new'
    end

    it "should have the edit view partial template of '/re_rule_definitions/<%=rule_name%>/edit'" do
      RulesEngine::Rule::<%=rule_class%>.options[:edit_partial].should == '/re_rule_definitions/<%=rule_name%>/edit'
    end
  end
  
  describe "setting the rule data" do
    before(:each) do
      @<%=rule_name%> = RulesEngine::Rule::<%=rule_class%>.new
      @<%=rule_name%>.data = valid_<%=rule_name%>_rule_data
    end  
    
    describe "the json data is valid" do
      it "should be valid" do
        @<%=rule_name%>.should be_valid
      end
            
      it "should set the title" do
        @<%=rule_name%>.title.should == "Rule Title"        
      end

      it "should set the message" do
        @<%=rule_name%>.message.should == "Twitter Message to Find"
      end

      it "should set the plan" do
        @<%=rule_name%>.plan.should == "Other Plan"
      end        

      it "should set the re_<%=rule_name%>_data_id" do
        @<%=rule_name%>.re_<%=rule_name%>_data_id.should == 1001
      end        
    end

    describe "the data is nil" do
      it "should set the title to nil" do
        @<%=rule_name%>.title.should_not be_nil
        @<%=rule_name%>.data = nil
        @<%=rule_name%>.title.should be_nil
      end
      
      it "should set the message to nil" do
        @<%=rule_name%>.message.should_not be_nil
        @<%=rule_name%>.data = nil
        @<%=rule_name%>.message.should be_nil
      end
      
      it "should set the 'plan' to nil" do
        @<%=rule_name%>.plan.should_not be_nil
        @<%=rule_name%>.data = nil
        @<%=rule_name%>.plan.should be_nil
      end              

      it "should set the 're_<%=rule_name%>_data_id' to nil" do
        @<%=rule_name%>.re_<%=rule_name%>_data_id.should_not be_nil
        @<%=rule_name%>.data = nil
        @<%=rule_name%>.re_<%=rule_name%>_data_id.should be_nil
      end              
    end
  end
  
  describe "the summary" do
    it "should show the plan" do
      <%=rule_name%> = RulesEngine::Rule::<%=rule_class%>.new
      <%=rule_name%>.stub!(:message).and_return("twitter message")
      <%=rule_name%>.stub!(:plan).and_return("mock")
      <%=rule_name%>.summary.should == "Look for \"twitter message\" and send matches to the plan : mock"
    end
  end
  
  describe "the data" do
    it "should be converted to a json string" do
      <%=rule_name%> = RulesEngine::Rule::<%=rule_class%>.new
      <%=rule_name%>.should_receive(:title).and_return("mock title")
      <%=rule_name%>.should_receive(:message).and_return("message")
      <%=rule_name%>.should_receive(:plan).and_return("plan")
      <%=rule_name%>.should_receive(:re_<%=rule_name%>_data_id).and_return(1002)
      <%=rule_name%>.data.should == '["mock title","message","plan","1002"]'
    end
  end
  
  describe "the expected_outcomes" do
    it "should be next and stop failure" do
      <%=rule_name%> = RulesEngine::Rule::<%=rule_class%>.new
      <%=rule_name%>.expected_outcomes.should include(:outcome => RulesEngine::Rule::Outcome::NEXT)
      <%=rule_name%>.expected_outcomes.should include(:outcome => RulesEngine::Rule::Outcome::STOP_FAILURE)
    end
  end
  
  describe "setting the rule attributes" do
    before(:each) do
      @<%=rule_name%> = RulesEngine::Rule::<%=rule_class%>.new
    end  
    
    it "should be valid with valid attributes" do
      @<%=rule_name%>.attributes = valid_attributes
      @<%=rule_name%>.should be_valid
    end            
  
    describe "setting the <%=rule_name%>_title" do
      it "should set the title" do
        @<%=rule_name%>.attributes = valid_attributes
        @<%=rule_name%>.title.should == 'Rule Title'
      end            
    
      it "should not be valid if the '<%=rule_name%>_title' attribute is missing" do
        @<%=rule_name%>.attributes = valid_attributes.except(:<%=rule_name%>_title)
        @<%=rule_name%>.should_not be_valid
        @<%=rule_name%>.errors.should include(:<%=rule_name%>_title)      
      end            
    
      it "should not be valid if the '<%=rule_name%>_title' attribute is blank" do
        @<%=rule_name%>.attributes = valid_attributes.merge(:<%=rule_name%>_title => "")
        @<%=rule_name%>.should_not be_valid
        @<%=rule_name%>.errors.should include(:<%=rule_name%>_title)
      end                
    end

    describe "setting the <%=rule_name%>_message" do
      it "should set the message" do
        @<%=rule_name%>.attributes = valid_attributes
        @<%=rule_name%>.message.should == 'The Message'
      end            
    
      it "should not be valid if the '<%=rule_name%>_message' attribute is missing" do
        @<%=rule_name%>.attributes = valid_attributes.except(:<%=rule_name%>_message)
        @<%=rule_name%>.should_not be_valid
        @<%=rule_name%>.errors.should include(:<%=rule_name%>_message)      
      end            
    
      it "should not be valid if the '<%=rule_name%>_message' attribute is blank" do
        @<%=rule_name%>.attributes = valid_attributes.merge(:<%=rule_name%>_message => "")
        @<%=rule_name%>.should_not be_valid
        @<%=rule_name%>.errors.should include(:<%=rule_name%>_message)
      end                
    end

    describe "setting the <%=rule_name%>_plan" do
      it "should be valid with valid '<%=rule_name%>_plan'" do
        @<%=rule_name%>.attributes = valid_attributes
        @<%=rule_name%>.should be_valid
        @<%=rule_name%>.plan.should == 'Next Plan'
      end            
      
      it "should not be valid if the '<%=rule_name%>_plan' attribute is missing" do
        @<%=rule_name%>.attributes = valid_attributes.except(:<%=rule_name%>_plan)        
        @<%=rule_name%>.should_not be_valid
        @<%=rule_name%>.errors.should include(:<%=rule_name%>_plan)
      end            

      it "should not be valid if the '<%=rule_name%>_plan' attribute is blank" do
        @<%=rule_name%>.attributes = valid_attributes.merge(:<%=rule_name%>_plan => "")        
        @<%=rule_name%>.should_not be_valid
        @<%=rule_name%>.errors.should include(:<%=rule_name%>_plan)
      end            
    end    
  end
  
  describe "before a rule is created" do
    it "should create a Re<%=rule_class%>Data record" do
      Re<%=rule_class%>Data.should_receive(:create).with(:since_id => 0).and_return(mock_model(Re<%=rule_class%>Data, :id => 1004))
      <%=rule_name%> = RulesEngine::Rule::<%=rule_class%>.new
      <%=rule_name%>.before_create
    end
    
    it "should set the re_<%=rule_name%>_data_id to the created record" do
      Re<%=rule_class%>Data.stub!(:create).with(:since_id => 0).and_return(mock_model(Re<%=rule_class%>Data, :id => 1004))
      <%=rule_name%> = RulesEngine::Rule::<%=rule_class%>.new
      <%=rule_name%>.before_create
      <%=rule_name%>.re_<%=rule_name%>_data_id.should == 1004
    end
  end
  
  describe "before a rule is updated" do
    # xit "There is nothing to do here"
  end
  
  describe "before a rule is destroyed" do
    it "should destroy the found record" do
      Re<%=rule_class%>Data.should_receive(:find_by_id).with(1004).and_return(re_<%=rule_name%>_data = mock_model(Re<%=rule_class%>Data))
      re_<%=rule_name%>_data.should_receive(:destroy)
      <%=rule_name%> = RulesEngine::Rule::<%=rule_class%>.new
      <%=rule_name%>.stub!(:re_<%=rule_name%>_data_id).and_return(1004)
      <%=rule_name%>.before_destroy
    end
    
    it "should ignore records that dop not exist" do
      Re<%=rule_class%>Data.stub!(:find_by_id).and_return(nil)
      <%=rule_name%> = RulesEngine::Rule::<%=rule_class%>.new
      <%=rule_name%>.before_destroy
    end            
  end
  
  describe "processing the rule" do
    before(:each) do
      @<%=rule_name%> = RulesEngine::Rule::<%=rule_class%>.new
      @<%=rule_name%>.stub!(:plan).and_return('sub_plan')
      @<%=rule_name%>.stub!(:message).and_return("sub message")
      @<%=rule_name%>.stub!(:re_<%=rule_name%>_data_id).and_return(1005)
      
      @re_<%=rule_name%>_data = mock_model(Re<%=rule_class%>Data)
      @re_<%=rule_name%>_data.stub!(:since_id).and_return(1234)
      @re_<%=rule_name%>_data.stub!(:update_attributes)
      Re<%=rule_class%>Data.stub!(:find_by_id).and_return(@re_<%=rule_name%>_data)
      
      RulesEngine::Process.runner.stub!(:create).and_return(1003)
      RulesEngine::Process.runner.stub!(:run).and_return(true)
      
      @twitter_search_results = mock('twitter_search_results')
      @twitter_search_results.stub!(:max_id).and_return(222)
      @twitter_search_results.stub!(:next_page).and_return(nil)
      
      @twitter_search = []
      @twitter_search.stub!(:containing)
      @twitter_search.stub!(:since)
      @twitter_search.stub!(:page)
      @twitter_search.stub!(:per_page)
      @twitter_search.stub!(:fetch).and_return(@twitter_search_results)
      
      Twitter::Search.stub!(:new).and_return(@twitter_search)
    end
    
    it "should get the current <%=rule_name%>_data" do
      Re<%=rule_class%>Data.should_receive(:find_by_id).with(1005).and_return(@re_<%=rule_name%>_data)
      @<%=rule_name%>.process(1003, {:origional => "data"})
    end

    it "should stop if the twitter data is missing" do
      Re<%=rule_class%>Data.should_receive(:find_by_id).with(1005).and_return(nil)
      @<%=rule_name%>.process(1003, {:origional => "data"}).outcome.should == RulesEngine::Rule::Outcome::STOP_FAILURE
    end

    it "should return outcome next if the plan was successful" do
      RulesEngine::Process.runner.stub!(:run).and_return(true)
      @<%=rule_name%>.process(1003, {}).outcome.should == RulesEngine::Rule::Outcome::NEXT
    end
        
    it "should set the the twitter search parameters" do
      @twitter_search.should_receive(:containing).with("sub message")
      @twitter_search.should_receive(:since).with(1234)
      
      @<%=rule_name%>.process(1003, {:origional => "data"})
    end

    describe "twitter search results" do
      before(:each) do
        RulesEngine::Publish.publisher.stub(:get).and_return('sub_plan_data')
        @twitter_search << mock('search_result', :text => "sub message one", :geo => "latlng one")
        @twitter_search << mock('search_result', :text => "sub message two", :geo => "latlng two")
      end
      
      it "should get the data for each sub plan" do
        RulesEngine::Publish.publisher.should_receive(:get).with('sub_plan').and_return('sub_plan_data_one')
        RulesEngine::Publish.publisher.should_receive(:get).with('sub_plan').and_return('sub_plan_data_two')
        @<%=rule_name%>.process(1003, {:origional => "data"})
      end
      
      it "should process each result" do
        RulesEngine::Process.runner.stub!(:create).and_return(1003, 1004)
        RulesEngine::Process.runner.should_receive(:run).with(1003, 'sub_plan_data', {:origional => "data", :tweet => "sub message one", :geo => "latlng one"}).and_return(true)
        RulesEngine::Process.runner.should_receive(:run).with(1004, 'sub_plan_data', {:origional => "data", :tweet => "sub message two", :geo => "latlng two"}).and_return(true)      
        @<%=rule_name%>.process(1003, {:origional => "data"})
      end

      it "should stop on the first error" do
        RulesEngine::Process.runner.stub!(:create).and_return(1003, 1004)
        RulesEngine::Process.runner.should_receive(:run).with(1003, anything, anything).and_return(false)
        RulesEngine::Process.runner.should_not_receive(:run).with(1004, anything, anything)
        @<%=rule_name%>.process(1003, {:origional => "data"})
      end

      describe "since_id" do
        it "should update the since_id with the results" do
          @twitter_search_results.stub!(:max_id).and_return(2002)
          @re_<%=rule_name%>_data.should_receive(:update_attributes).with(:since_id => 2002)
          @<%=rule_name%>.process(1003, {:origional => "data"})
        end

        it "should not update the since_id if less than the current" do
          @twitter_search_results.should_receive(:max_id).and_return(100)
          @re_<%=rule_name%>_data.should_receive(:update_attributes).with(:since_id => 1234)
          @<%=rule_name%>.process(1003, {:origional => "data"})
        end
      end
          
      it "should return outcome stop failure if the plan failed" do
        RulesEngine::Process.runner.stub!(:run).and_return(false)
        @<%=rule_name%>.process(1003, {}).outcome.should == RulesEngine::Rule::Outcome::STOP_FAILURE
      end      
    end  
  end
end


describe ReWorkflowRulesController, :type => :controller  do
  integrate_views
  
  describe "RulesEngine::Rule::<%=rule_class%>" do
  
    before(:each) do
      controller.instance_eval { flash.stub!(:sweep) }

      RulesEngine::Discovery.discover!
    
      controller.stub!(:rules_engine_reader_access_required).and_return(true)
      controller.stub!(:rules_engine_editor_access_required).and_return(true)

      @re_workflow = ReWorkflow.make
      ReWorkflow.stub!(:find).and_return(@re_workflow)
    end  
  
    describe "help" do
      it "should assign the tweet reader_rule class" do
        get :help, :rule_class_name => "RulesEngine::Rule::<%=rule_class%>"
        assigns[:rule_class].should == RulesEngine::Rule::<%=rule_class%>
      end
    end
  
    describe "new" do
      it "show the new form class" do
        get :new, :rule_class_name => "RulesEngine::Rule::<%=rule_class%>"
        response.should have_tag("form#re_rule_new_form") do
          with_tag("input#<%=rule_name%>_title")
          with_tag("input#<%=rule_name%>_message")
          with_tag("input#<%=rule_name%>_plan")
        end  
      end
    end

    describe "edit" do
      it "show the edit form" do
        re_rule = ReRule.make(:re_workflow_id => @re_workflow.id, 
                              :rule_class_name => "RulesEngine::Rule::<%=rule_class%>",
                              :data => valid_<%=rule_name%>_rule_data)
        ReRule.stub!(:find).and_return(re_rule)
      
        get :edit, :re_workflow_id => @re_workflow.id, :re_rule_id => 1001, :rule_class_name => "RulesEngine::Rule::<%=rule_class%>"
        response.should have_tag("form#re_rule_edit_form") do
          with_tag("input#<%=rule_name%>_title", :value => 'Rule Title')     
          with_tag("input#<%=rule_name%>_message", :value => 'Twitter Message to Find')     
          with_tag("input#<%=rule_name%>_plan", :value => 'Other Plan')     
        end  
      end
    end
  end
end