require File.expand_path(File.dirname(__FILE__) + '/spec_helper') class Tester include ::Trigga::ParamFu end describe ::Trigga::ParamFu do before(:each) do @t = Tester.new end describe "class methods" do describe "key_with_id" do it "should add '_id' onto the given symbol" do Tester.key_with_id(:blart).should == :blart_id end end describe "obj_or_id" do describe "when the given hash already contains :(given_key)_id" do it "should not change the value of that _id key" do @my_obj = mock("object") @my_obj.stub!(:id).and_return(456) @my_hash = {:my_key_id=>123, :my_obj=>@my_obj} Tester.obj_or_id( @my_hash, :my_key ) @my_hash[:my_key_id].should == 123 end end describe "when the given hash does not already contain :(given_key)_id" do describe "and the given hash contains the given key without an added _id" do it "should set the :(given_key)_id to the id of the object" do @mock_obj = mock("obj") @mock_obj.stub!(:id).and_return(123) Tester.obj_or_id( {:my_obj=>@mock_obj}, :my_obj ).should == 123 end end end end describe "require_param" do context "when given a single key" do context "when key is not present in opts" do it "should raise an ArgumentError" do lambda{ Tester.require_param( {:key1=>'value1'}, :key2 ) }.should raise_error(ArgumentError) end end context "when key is present in opts" do it "should not raise an error" do lambda{ Tester.require_param( {:key1=>'value1'}, :key1 ) }.should_not raise_error(ArgumentError) end end end context "when given multiple keys" do context "when all keys are present" do it "should not raise an error" do lambda{ Tester.require_param( {:key1=>'value1', :key2=>'value2'}, :key2, :key1 ) }.should_not raise_error(ArgumentError) end end context "when at least one key is not present" do it "should raise an ArgumentError " do lambda{ Tester.require_param( {:key1=>'value1', :key2=>'value2'}, :key2, :key1, :key3 ) }.should raise_error(ArgumentError) end end end end describe "require_obj_or_id" do context "when the key is present" do it "should not raise an error" do lambda{ Tester.require_obj_or_id( {:obj_name=>'value1'}, :obj_name ) }.should_not raise_error(ArgumentError) end end context "when the key is not present" do context "when the key suffixed with _id is present" do it "should not raise an error" do lambda{ Tester.require_obj_or_id( {:obj_id=>'value1'}, :obj ) }.should_not raise_error(ArgumentError) end end context "when the key is not present even suffixed with _id" do it "should raise an error" do lambda{ Tester.require_obj_or_id( {:key1=>'value1', :key2_id=>123}, :key3 ) }.should raise_error(ArgumentError) end end end end describe "require_one_of" do context "when at least one of the given keys is contained in opts" do it "should not raise an error" do lambda{ Tester.require_one_of( {:obj=>'value1'}, :foo, :bar, :obj ) }.should_not raise_error(ArgumentError) end end context "when none of the given keys are contained in opts" do it "should raise an error" do lambda{ Tester.require_one_of( {:obj=>'value1'}, :foo, :bar ) }.should raise_error(ArgumentError) end end end describe "id_or_name_condition" do it "should return a hash" do Tester.id_or_name_condition('mymodel', 'string_value').should be_a Hash end it "should have a key for :where" do Tester.id_or_name_condition('mymodel', 'string_value').keys.should include(:where) end it "should have a key for :values" do Tester.id_or_name_condition('mymodel', 'string_value').keys.should include(:values) end context "when given a string value" do it "should include '(table).name like ?' in the where clause" do Tester.id_or_name_condition('mymodel', 'string_value')[:where].should =~ /mymodel\.name\s*like\s*\?/i end it "should include the given value in values, wrapped in wildcard markers" do Tester.id_or_name_condition('mymodel', 'string_value')[:values].should == '%string_value%' end context "and the value has an id in brackets on the end" do it "should strip the brackets and value" do Tester.id_or_name_condition('mymodel', 'string_value (1234)')[:values].should_not =~ /\([0-9]*\)/ end it "should strip any space before the brackets" do Tester.id_or_name_condition('mymodel', 'string_value (1234)')[:values].should == "%string_value%" end end end context "when given an integer value" do it "should include '(table).id == ?' in the where clause" do Tester.id_or_name_condition('mymodel', '2')[:where].should =~ /mymodel\.id\s*=\s*\?/i end it "should include the given value in values, as an integer" do Tester.id_or_name_condition('mymodel', '2')[:values].should == 2 end end end describe "parse_field_definition" do before(:each) do @params = { :param_1 => 'param_1 value' } @model_class = mock("model class") @model_class.stub!(:table_name).and_return( 'model_class_table_name' ) @param_name = :param_name @definition = { :operator=>'=', :field_name=>'field_name'} end it "should return a Hash" do Tester.parse_field_definition( @params, @model_class, @param_name, @definition ).should be_a(Hash) end describe "returned Hash" do it "should have a key for :where" do Tester.parse_field_definition( @params, @model_class, @param_name, @definition )[:where].should_not be_nil end it "should have a key for :values" do Tester.parse_field_definition( @params, @model_class, @param_name, @definition )[:values].should_not be_nil end context "when the given opts has a key matching the given param_name" do before(:each) do @param_name = :param_1 end context "and the param value is not empty" do it "should add an element to the :where key" do Tester.parse_field_definition( @params, @model_class, @param_name, @definition )[:where].size.should == 1 end describe "where clause" do it "should be wrapped in brackets" do Tester.parse_field_definition( @params, @model_class, @param_name, @definition )[:where][0].should =~ /^\s*\(.*\)\s*$/ end describe "inside the brackets" do before(:each) do @inside_the_brackets = Tester.parse_field_definition( @params, @model_class, @param_name, @definition )[:where][0].gsub(/^\s*\((.*)\)\s*$/, '\1') end it "should call scoped_field_name " do Tester.should_receive(:scoped_field_name).and_return('blart') Tester.parse_field_definition( @params, @model_class, @param_name, @definition ) end describe "scoped_field_name args" do it "should start with the model class" do Tester.should_receive(:scoped_field_name) do |args| args[0].should == @model_class 'blart' end Tester.parse_field_definition( @params, @model_class, @param_name, @definition ) end context "When the definition has a :fieldname" do before(:each) do @definition[:field_name] = 'field_name' end it "should pass the given :field_name as the second arg" do Tester.should_receive(:scoped_field_name) do |args| args[1].should == 'field_name' 'blart' end Tester.parse_field_definition( @params, @model_class, @param_name, @definition ) end end context "When the definition has no :fieldname" do before(:each) do @definition[:field_name] = nil end it "should pass the given param_name converted to a string as the second arg" do Tester.should_receive(:scoped_field_name) do |args| args[1].should == 'param_1' 'blart' end Tester.parse_field_definition( @params, @model_class, @param_name, @definition ) end end context "when the definitions fieldname is an array" do before(:each) do @definition[:field_name] = ["field_name_1", "other_table.field_name_2"] end it "should call scoped_field_name with each element" do Tester.should_receive(:scoped_field_name) do |args| args[1].should == 'field_name_1' 'blart' end Tester.should_receive(:scoped_field_name) do |args| args[1].should == 'other_table.field_name_2' 'blart' end Tester.parse_field_definition( @params, @model_class, @param_name, @definition ) end it "should join the fieldname conditions together with OR" do Tester.parse_field_definition( @params, @model_class, @param_name, @definition )[:where][0].should == "( model_class_table_name.field_name_1 = (?) OR other_table.field_name_2 = (?) )" end it "should add the value to the :values clause once for each element of the array" do Tester.parse_field_definition( @params, @model_class, @param_name, @definition )[:values].size.should == 2 end end end context "When the definition has a :operator" do before(:each) do @definition[:operator] = 'my_operator' @inside_the_brackets = Tester.parse_field_definition( @params, @model_class, @param_name, @definition )[:where][0].gsub(/^\s*\((.*)\)\s*$/, '\1') end it "should use the :operator" do @inside_the_brackets.should =~ /.*\bmy_operator\b.*/ end end context "When the definition has no :operator" do before(:each) do @definition[:operator] = nil @inside_the_brackets = Tester.parse_field_definition( @params, @model_class, @param_name, @definition )[:where][0].gsub(/^\s*\((.*)\)\s*$/, '\1') end it "should use = as the :operator" do @inside_the_brackets.should =~ /[^=]+\s*=\s*[^=]+/ end end it "should end with (?)" do @inside_the_brackets.should =~ /\(\?\)\s*$/ end end end context "when the given :operator matches 'like'" do before(:each) do @definition[:operator] = " LIKE " end it "should add the corresponding value, converted to a like condition, to the :values key" do Tester.parse_field_definition( @params, @model_class, @param_name, @definition )[:values].should == ['%param_1%value%'] end end it "should add the corresponding value to the :values key" do Tester.parse_field_definition( @params, @model_class, @param_name, @definition )[:values].should == ['param_1 value'] end end context "when the given value is empty" do before(:each) do @params = {:param_1=>'', :param_2=>'dave'} @param_name = :param_1 end it "should not add the key to the where clause" do Tester.parse_field_definition( @params, @model_class, @param_name, @definition )[:where].should be_empty end it "should not add the value to the :values key" do Tester.parse_field_definition( @params, @model_class, @param_name, @definition )[:values].should_not include('') end end end end end describe "scoped_field_name" do before do @model_class = mock("model class") @model_class.stub!(:table_name).and_return( 'model_class_table_name' ) end context "when the given field_name contains a ." do it "should just return the given field_name" do Tester.scoped_field_name(@model_class, 'blart.flange').should == 'blart.flange' end end context "when the given field_name does not contain a ." do it "should call table_name on the model_class" do @model_class.should_receive(:table_name).and_return( 'model_class_table_name' ) Tester.scoped_field_name(@model_class, 'blart') end it "should return the given field_name" do Tester.scoped_field_name(@model_class, 'flange').should == 'model_class_table_name.flange' end end end describe "model_conditions" do before(:each) do @params = { :param_1 => 'param_1 value' } @model_class = mock("model class") @mock_parsed_field_def_1 = {:where=>['where 1'], :values=>['values 1']} @mock_parsed_field_def_2 = {:where=>['where 2'], :values=>['values 2']} Tester.stub!(:parse_field_definition).and_return( @mock_parsed_field_def_1, @mock_parsed_field_def_2 ) @definitions = { :key=>'=', :field_name=>'field_name'} end it "should return a Hash" do Tester.model_conditions( @params, @model_class, @definitions ).should be_a(Hash) end describe "returned Hash" do it "should have a key for :where" do Tester.model_conditions( @params, @model_class, @definitions )[:where].should_not be_nil end it "should have a key for :values" do Tester.model_conditions( @params, @model_class, @definitions )[:values].should_not be_nil end end context "for each given field_def" do before(:each) do @definitions = { :field_name_1 => (@mock_definition_1={}), :field_name_2 => (@mock_definition_2={}) } end it "should call parse_field_definition" do Tester.should_receive(:parse_field_definition).twice.and_return( @mock_parsed_field_def_1, @mock_parsed_field_def_2 ) Tester.model_conditions( @params, @model_class, @definitions ) end describe "parse_field_definition call params" do it "should pass the given opts" do Tester.should_receive(:parse_field_definition).with( @params, anything, anything, anything ).twice.and_return( @mock_parsed_field_def_1, @mock_parsed_field_def_2 ) Tester.model_conditions( @params, @model_class, @definitions ) end it "should pass the given model class" do Tester.should_receive(:parse_field_definition).with( anything, @model_class, anything, anything ).twice.and_return( @mock_parsed_field_def_1, @mock_parsed_field_def_2 ) Tester.model_conditions( @params, @model_class, @definitions ) end it "should pass each field_name" do Tester.should_receive(:parse_field_definition) do |args| args[2].should == :field_name_2 @mock_parsed_field_def_2 end Tester.should_receive(:parse_field_definition) do |args| args[2].should == :field_name_1 @mock_parsed_field_def_1 end Tester.model_conditions( @params, @model_class, @definitions ) end it "should pass the field_name's definition" do Tester.should_receive(:parse_field_definition) do |args| args[3].should == @mock_definition_1 @mock_parsed_field_def_1 end Tester.should_receive(:parse_field_definition) do |args| args[3].should == @mock_definition_2 @mock_parsed_field_def_2 end Tester.model_conditions( @params, @model_class, @definitions ) end end it "should add the :where key from the parsed field definition to the :where key of the return hash " do Tester.model_conditions( @params, @model_class, @definitions )[:where].should == ['where 1', 'where 2'] end it "should add the :values key from the parsed field definition to the :values key of the return hash " do Tester.model_conditions( @params, @model_class, @definitions )[:values].should == ['values 1', 'values 2'] end end end describe "params_to_conditions" do before(:each) do @mock_params = mock('params') @model_class_1 = "model class 1" @model_class_2 = "model class 2" @models = { @model_class_1 => 'model class def 1', @model_class_2 => 'model class def 2' } @mock_parsed_model_def_1 = {:where=>['where 1'], :values=>['values 1']} @mock_parsed_model_def_2 = {:where=>['where 2'], :values=>['values 2']} Tester.stub!(:model_conditions).and_return( @mock_parsed_model_def_1, @mock_parsed_model_def_2 ) end context "when not given a :params key" do it "should raise an ArgumentError" do lambda{ Tester.params_to_conditions(:blart=>'flange', :models=>'models') }.should raise_error(ArgumentError) end end context "when not given a :models key" do it "should raise an ArgumentError" do lambda{ Tester.params_to_conditions(:blart=>'flange', :params=>'params') }.should raise_error(ArgumentError) end end context "for each given model" do before(:each) do end it "should call model_conditions" do Tester.should_receive(:model_conditions).twice.and_return( @mock_parsed_model_def_1, @mock_parsed_model_def_2 ) Tester.params_to_conditions( :params=>@mock_params, :models=>@models ) end describe "model_conditions_call_params" do it "should pass on the given :params" do Tester.should_receive(:model_conditions).with(@mock_params, anything, anything).twice.and_return( @mock_parsed_model_def_1, @mock_parsed_model_def_2 ) Tester.params_to_conditions( :params=>@mock_params, :models=>@models ) end it "should pass each model class" do Tester.should_receive(:model_conditions) do |args| args[1].should == 'model class 1' @mock_parsed_model_def_1 end Tester.should_receive(:model_conditions) do |args| args[1].should == 'model class 2' @mock_parsed_model_def_2 end Tester.params_to_conditions( :params=>@mock_params, :models=>@models ) end it "should pass the models field definitions" do Tester.should_receive(:model_conditions) do |args| args[2].should == 'model class def 1' @mock_parsed_model_def_1 end Tester.should_receive(:model_conditions) do |args| args[2].should == 'model class def 2' @mock_parsed_model_def_2 end Tester.params_to_conditions( :params=>@mock_params, :models=>@models ) end end end describe "returned value" do it "should be an array" do Tester.params_to_conditions( :params=>@mock_params, :models=>@models ).should be_a(Array) end describe "first element" do it "should be a string" do Tester.params_to_conditions( :params=>@mock_params, :models=>@models )[0].should be_a(String) end it "should have the :where keys from the parsed model definitions joined with AND " do Tester.params_to_conditions( :params=>@mock_params, :models=>@models )[0].should == "where 1 AND where 2" end end describe "subsequent elements" do it "should be the values from the parsed model definitions" do Tester.params_to_conditions( :params=>@mock_params, :models=>@models )[1].should == 'values 1' Tester.params_to_conditions( :params=>@mock_params, :models=>@models )[2].should == 'values 2' end end end end end describe "instance_methods" do it "should not raise an error" do lambda { @t.require_obj_or_id( {:key=>'val'}, :key ) }.should_not raise_error end end end