Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Adding a lot more specs, including some tweaks

  • Loading branch information...
commit 352436d0e3cf74ff770f3dbf0ad3528394689252 1 parent 92450ff
@pat pat authored
View
5 lib/thinking_sphinx.rb
@@ -20,7 +20,7 @@ module ThinkingSphinx
module Version #:nodoc:
Major = 0
Minor = 9
- Tiny = 6
+ Tiny = 7
String = [Major, Minor, Tiny].join('.')
end
@@ -67,6 +67,9 @@ def self.deltas_enabled=(value)
@@deltas_enabled = value
end
+ # Checks to see if MySQL will allow simplistic GROUP BY statements. If not,
+ # or if not using MySQL, this will return false.
+ #
def self.use_group_by_shortcut?
::ActiveRecord::ConnectionAdapters.constants.include?("MysqlAdapter") &&
::ActiveRecord::Base.connection.is_a?(
View
10 lib/thinking_sphinx/association.rb
@@ -122,16 +122,16 @@ def self.casted_options(klass, ref)
options[:class_name] = klass.name
options[:foreign_key] ||= "#{ref.name}_id"
- foreign_type = klass.connection.quote_column_name ref.options[:foreign_type]
+ quoted_foreign_type = klass.connection.quote_column_name ref.options[:foreign_type]
case options[:conditions]
when nil
- options[:conditions] = "::ts_join_alias::.#{foreign_type} = '#{klass.name}'"
+ options[:conditions] = "::ts_join_alias::.#{quoted_foreign_type} = '#{klass.name}'"
when Array
- options[:conditions] << "::ts_join_alias::.#{foreign_type} = '#{klass.name}'"
+ options[:conditions] << "::ts_join_alias::.#{quoted_foreign_type} = '#{klass.name}'"
when Hash
- options[:conditions].merge!(foreign_type => klass.name)
+ options[:conditions].merge!(ref.options[:foreign_type] => klass.name)
else
- options[:conditions] << " AND ::ts_join_alias::.#{foreign_type} = '#{klass.name}'"
+ options[:conditions] << " AND ::ts_join_alias::.#{quoted_foreign_type} = '#{klass.name}'"
end
options
View
5 spec/spec_helper.rb
@@ -23,6 +23,11 @@
# sphinx.start
end
+ config.before :each do
+ NotAMock::CallRecorder.instance.reset
+ NotAMock::Stubber.instance.reset
+ end
+
config.after :all do
# sphinx.stop
View
2  spec/sphinx_helper.rb
@@ -1,4 +1,6 @@
require 'active_record'
+require 'active_record/connection_adapters/mysql_adapter'
+require 'active_record/connection_adapters/postgresql_adapter'
require 'yaml'
require 'spec/fixtures/models'
View
4 spec/unit/thinking_sphinx/active_record/delta_spec.rb
@@ -17,6 +17,10 @@
:after_commit, [:toggle_delta]
)
end
+
+ it "should have an after_commit method by default" do
+ Person.instance_methods.should include("after_commit")
+ end
end
describe "save_with_after_commit_callback method" do
View
63 spec/unit/thinking_sphinx/active_record/search_spec.rb
@@ -0,0 +1,63 @@
+require 'spec/spec_helper'
+
+describe "ThinkingSphinx::ActiveRecord::Search" do
+ it "should add search_for_ids to ActiveRecord::Base" do
+ ActiveRecord::Base.methods.should include("search_for_ids")
+ end
+
+ it "should add search_for_ids to ActiveRecord::Base" do
+ ActiveRecord::Base.methods.should include("search")
+ end
+
+ describe "search_for_ids method" do
+ before :each do
+ ThinkingSphinx::Search.stub_method(:search_for_ids => true)
+ end
+
+ after :each do
+ ThinkingSphinx::Search.unstub_method(:search_for_ids)
+ end
+
+ it "should call ThinkingSphinx::Search#search_for_ids with the class option set" do
+ Person.search_for_ids("search")
+
+ ThinkingSphinx::Search.should have_received(:search_for_ids).with(
+ "search", :class => Person
+ )
+ end
+
+ it "should override the class option" do
+ Person.search_for_ids("search", :class => Friendship)
+
+ ThinkingSphinx::Search.should have_received(:search_for_ids).with(
+ "search", :class => Person
+ )
+ end
+ end
+
+ describe "search method" do
+ before :each do
+ ThinkingSphinx::Search.stub_method(:search => true)
+ end
+
+ after :each do
+ ThinkingSphinx::Search.unstub_method(:search)
+ end
+
+ it "should call ThinkingSphinx::Search#search with the class option set" do
+ Person.search("search")
+
+ ThinkingSphinx::Search.should have_received(:search).with(
+ "search", :class => Person
+ )
+ end
+
+ it "should override the class option" do
+ Person.search("search", :class => Friendship)
+
+ ThinkingSphinx::Search.should have_received(:search).with(
+ "search", :class => Person
+ )
+ end
+ end
+end
View
74 spec/unit/thinking_sphinx/active_record_spec.rb
@@ -8,8 +8,9 @@ class TestModel < ActiveRecord::Base; end
end
TestModule::TestModel.stub_methods(
- :before_save => true,
- :after_commit => true
+ :before_save => true,
+ :after_commit => true,
+ :after_destroy => true
)
@index = ThinkingSphinx::Index.stub_instance(:delta? => false)
@@ -74,6 +75,20 @@ class TestModel < ActiveRecord::Base; end
TestModule::TestModel.should_not have_received(:after_commit)
end
+ it "should add an after_destroy hook with delta indexing enabled" do
+ @index.stub_method(:delta? => true)
+
+ TestModule::TestModel.define_index do; end
+
+ TestModule::TestModel.should have_received(:after_destroy).with(:toggle_deleted)
+ end
+
+ it "should add an after_destroy hook with delta indexing disabled" do
+ TestModule::TestModel.define_index do; end
+
+ TestModule::TestModel.should have_received(:after_destroy).with(:toggle_deleted)
+ end
+
it "should return the new index" do
TestModule::TestModel.define_index.should == @index
end
@@ -84,4 +99,59 @@ class TestModel < ActiveRecord::Base; end
Person.to_crc32.should be_a_kind_of(Integer)
end
end
+
+ describe "toggle_deleted method" do
+ before :each do
+ @configuration = ThinkingSphinx::Configuration.stub_instance(
+ :address => "an address",
+ :port => 123
+ )
+ @client = Riddle::Client.stub_instance(:update => true)
+ @person = Person.new
+
+ ThinkingSphinx::Configuration.stub_method(:new => @configuration)
+ Riddle::Client.stub_method(:new => @client)
+ Person.indexes.each { |index| index.stub_method(:delta? => false) }
+ end
+
+ after :each do
+ ThinkingSphinx::Configuration.unstub_method(:new)
+ Riddle::Client.unstub_method(:new)
+ Person.indexes.each { |index| index.unstub_method(:delta?) }
+ end
+
+ it "should create a client using the Configuration's address and port" do
+ @person.toggle_deleted
+
+ Riddle::Client.should have_received(:new).with(
+ @configuration.address, @configuration.port
+ )
+ end
+
+ it "should update the core index's deleted flag" do
+ @person.toggle_deleted
+
+ @client.should have_received(:update).with(
+ "person_core", ["sphinx_deleted"], {@person.id => 1}
+ )
+ end
+
+ it "should update the delta index's deleted flag if delta indexing is enabled" do
+ Person.indexes.each { |index| index.stub_method(:delta? => true) }
+
+ @person.toggle_deleted
+
+ @client.should have_received(:update).with(
+ "person_delta", ["sphinx_deleted"], {@person.id => 1}
+ )
+ end
+
+ it "shouldn't update the delta index if delta indexing is disabled" do
+ @person.toggle_deleted
+
+ @client.should_not have_received(:update).with(
+ "person_delta", ["sphinx_deleted"], {@person.id => 1}
+ )
+ end
+ end
end
View
247 spec/unit/thinking_sphinx/association_spec.rb
@@ -0,0 +1,247 @@
+require 'spec/spec_helper'
+
+describe ThinkingSphinx::Association do
+ describe "class-level children method" do
+ before :each do
+ @normal_reflection = ::ActiveRecord::Reflection::AssociationReflection.stub_instance(
+ :options => {:polymorphic => false}
+ )
+ @normal_association = ThinkingSphinx::Association.stub_instance
+ @poly_reflection = ::ActiveRecord::Reflection::AssociationReflection.stub_instance(
+ :options => {:polymorphic => true},
+ :macro => :has_many,
+ :name => "polly",
+ :active_record => "AR"
+ )
+ @non_poly_reflection = ::ActiveRecord::Reflection::AssociationReflection.stub_instance
+
+ Person.stub_method(:reflect_on_association => @normal_reflection)
+ ThinkingSphinx::Association.stub_methods(
+ :new => @normal_association,
+ :polymorphic_classes => [Person, Person],
+ :casted_options => {:casted => :options}
+ )
+ ::ActiveRecord::Reflection::AssociationReflection.stub_method(
+ :new => @non_poly_reflection
+ )
+ end
+
+ it "should return an empty array if no association exists" do
+ Person.stub_method(:reflect_on_association => nil)
+
+ ThinkingSphinx::Association.children(Person, :assoc).should == []
+ end
+
+ it "should return a single association instance in an array if assocation isn't polymorphic" do
+ ThinkingSphinx::Association.children(Person, :assoc).should == [@normal_association]
+ end
+
+ it "should return multiple association instances for polymorphic associations" do
+ Person.stub_method(:reflect_on_association => @poly_reflection)
+
+ ThinkingSphinx::Association.children(Person, :assoc).should ==
+ [@normal_association, @normal_association]
+ end
+
+ it "should generate non-polymorphic 'casted' associations for each polymorphic possibility" do
+ Person.stub_method(:reflect_on_association => @poly_reflection)
+
+ ThinkingSphinx::Association.children(Person, :assoc)
+
+ ThinkingSphinx::Association.should have_received(:casted_options).with(
+ Person, @poly_reflection
+ ).twice
+
+ ::ActiveRecord::Reflection::AssociationReflection.should have_received(:new).with(
+ :has_many, :polly_Person, {:casted => :options}, "AR"
+ ).twice
+
+ ThinkingSphinx::Association.should have_received(:new).with(
+ nil, @non_poly_reflection
+ ).twice
+ end
+ end
+
+ describe "instance-level children method" do
+ it "should return the children associations for the given association" do
+ @reflection = ::ActiveRecord::Reflection::AssociationReflection.stub_instance(
+ :klass => :klass
+ )
+ @association = ThinkingSphinx::Association.new(nil, @reflection)
+ ThinkingSphinx::Association.stub_method(:children => :result)
+
+ @association.children(:assoc).should == :result
+ ThinkingSphinx::Association.should have_received(:children).with(:klass, :assoc, @association)
+ end
+ end
+
+ describe "join_to method" do
+ before :each do
+ @parent_join = ::ActiveRecord::Associations::ClassMethods::JoinDependency::JoinAssociation.stub_instance
+ @join = ::ActiveRecord::Associations::ClassMethods::JoinDependency::JoinAssociation.stub_instance
+ @parent = ThinkingSphinx::Association.stub_instance(:join_to => true, :join => nil)
+ @base_join = Object.stub_instance(:joins => [:a, :b, :c])
+
+ ::ActiveRecord::Associations::ClassMethods::JoinDependency::JoinAssociation.stub_method(:new => @join)
+ end
+
+ it "should call the parent's join_to if parent has no join" do
+ @assoc = ThinkingSphinx::Association.new(@parent, :ref)
+
+ @assoc.join_to(@base_join)
+
+ @parent.should have_received(:join_to).with(@base_join)
+ end
+
+ it "should not call the parent's join_to if it already has a join" do
+ @assoc = ThinkingSphinx::Association.new(@parent, :ref)
+ @parent.stub_method(:join => @parent_join)
+
+ @assoc.join_to(@base_join)
+
+ @parent.should_not have_received(:join_to)
+ end
+
+ it "should define the join association with a JoinAssociation instance" do
+ @assoc = ThinkingSphinx::Association.new(@parent, :ref)
+
+ @assoc.join_to(@base_join).should == @join
+ @assoc.join.should == @join
+ end
+ end
+
+ describe "to_sql method" do
+ before :each do
+ @reflection = ::ActiveRecord::Reflection::AssociationReflection.stub_instance(
+ :klass => Person
+ )
+ @association = ThinkingSphinx::Association.new(nil, @reflection)
+ @parent = Object.stub_instance(:aliased_table_name => "ALIAS TABLE NAME")
+ @join = ::ActiveRecord::Associations::ClassMethods::JoinDependency::JoinAssociation.stub_instance(
+ :association_join => "full association join SQL",
+ :parent => @parent
+ )
+ @association.join = @join
+ end
+
+ it "should return the join's association join value" do
+ @association.to_sql.should == "full association join SQL"
+ end
+
+ it "should replace ::ts_join_alias:: with the aliased table name" do
+ @join.stub_method(:association_join => "text with ::ts_join_alias:: gone")
+
+ @association.to_sql.should == "text with `ALIAS TABLE NAME` gone"
+ end
+ end
+
+ describe "is_many? method" do
+ before :each do
+ @parent = ThinkingSphinx::Association.stub_instance(
+ :is_many? => :parent_is_many
+ )
+ @reflection = ::ActiveRecord::Reflection::AssociationReflection.stub_instance(
+ :macro => :has_many
+ )
+ end
+
+ it "should return true if association is either a has_many or a habtm" do
+ association = ThinkingSphinx::Association.new(@parent, @reflection)
+ association.is_many?.should be_true
+
+ @reflection.stub_method(:macro => :has_and_belongs_to_many)
+ association.is_many?.should be_true
+ end
+
+ it "should return the parent value if not a has many or habtm and there is a parent" do
+ association = ThinkingSphinx::Association.new(@parent, @reflection)
+ @reflection.stub_method(:macro => :belongs_to)
+ association.is_many?.should == :parent_is_many
+ end
+
+ it "should return false if no parent and not a has many or habtm" do
+ association = ThinkingSphinx::Association.new(nil, @reflection)
+ @reflection.stub_method(:macro => :belongs_to)
+ association.is_many?.should be_false
+ end
+ end
+
+ describe "ancestors method" do
+ it "should return an array of associations - including all parents" do
+ parent = ThinkingSphinx::Association.stub_instance(:ancestors => [:all, :ancestors])
+ association = ThinkingSphinx::Association.new(parent, @reflection)
+ association.ancestors.should == [:all, :ancestors, association]
+ end
+ end
+
+ describe "polymorphic_classes method" do
+ it "should return all the polymorphic result types as classes" do
+ Person.connection.stub_method(:select_all => [
+ {"person_type" => "Person"},
+ {"person_type" => "Friendship"}
+ ])
+ ref = Object.stub_instance(
+ :active_record => Person,
+ :options => {:foreign_type => "person_type"}
+ )
+
+ ThinkingSphinx::Association.send(:polymorphic_classes, ref).should == [Person, Friendship]
+ end
+ end
+
+ describe "casted_options method" do
+ before :each do
+ @options = {
+ :foreign_key => "thing_id",
+ :foreign_type => "thing_type",
+ :polymorphic => true
+ }
+ @reflection = ::ActiveRecord::Reflection::AssociationReflection.stub_instance(
+ :options => @options
+ )
+ end
+
+ it "should return a new options set for a specific class" do
+ ThinkingSphinx::Association.send(:casted_options, Person, @reflection).should == {
+ :polymorphic => nil,
+ :class_name => "Person",
+ :foreign_key => "thing_id",
+ :foreign_type => "thing_type",
+ :conditions => "::ts_join_alias::.`thing_type` = 'Person'"
+ }
+ end
+
+ it "should append to existing Array of conditions" do
+ @options[:conditions] = ["first condition"]
+ ThinkingSphinx::Association.send(:casted_options, Person, @reflection).should == {
+ :polymorphic => nil,
+ :class_name => "Person",
+ :foreign_key => "thing_id",
+ :foreign_type => "thing_type",
+ :conditions => ["first condition", "::ts_join_alias::.`thing_type` = 'Person'"]
+ }
+ end
+
+ it "should merge to an existing Hash of conditions" do
+ @options[:conditions] = {"field" => "value"}
+ ThinkingSphinx::Association.send(:casted_options, Person, @reflection).should == {
+ :polymorphic => nil,
+ :class_name => "Person",
+ :foreign_key => "thing_id",
+ :foreign_type => "thing_type",
+ :conditions => {"field" => "value", "thing_type" => "Person"}
+ }
+ end
+
+ it "should append to an existing String of conditions" do
+ @options[:conditions] = "first condition"
+ ThinkingSphinx::Association.send(:casted_options, Person, @reflection).should == {
+ :polymorphic => nil,
+ :class_name => "Person",
+ :foreign_key => "thing_id",
+ :foreign_type => "thing_type",
+ :conditions => "first condition AND ::ts_join_alias::.`thing_type` = 'Person'"
+ }
+ end
+ end
+end
View
288 spec/unit/thinking_sphinx/attribute_spec.rb
@@ -1,7 +1,21 @@
require 'spec/spec_helper'
describe ThinkingSphinx::Attribute do
- describe "to_select_sql method" do
+ describe '#initialize' do
+ it 'raises if no columns are provided so that configuration errors are easier to track down' do
+ lambda {
+ ThinkingSphinx::Attribute.new([])
+ }.should raise_error(RuntimeError)
+ end
+
+ it 'raises if an element of the columns param is an integer - as happens when you use id instead of :id - so that configuration errors are easier to track down' do
+ lambda {
+ ThinkingSphinx::Attribute.new([1234])
+ }.should raise_error(RuntimeError)
+ end
+ end
+
+ describe "to_select_sql method with MySQL" do
before :each do
@index = Person.indexes.first
@index.link!
@@ -36,6 +50,40 @@
end
end
+ describe "to_select_sql method with PostgreSQL" do
+ before :each do
+ @index = Person.indexes.first
+ Person.connection.class.stub_method(
+ :name => "ActiveRecord::ConnectionAdapters::PostgreSQLAdapter"
+ )
+ @index.link!
+ end
+
+ it "should concat with spaces if there's more than one non-integer column" do
+ @index.attributes[0].to_select_sql.should match(/|| ' ' ||/)
+ end
+
+ it "should concat with spaces if there's more than one association for a non-integer column" do
+ @index.attributes[1].to_select_sql.should match(/|| ' ' ||/)
+ end
+
+ it "should concat with commas if there's multiple integer columns" do
+ @index.attributes[2].to_select_sql.should match(/|| ',' ||/)
+ end
+
+ it "should concat with commas if there's more than one association for an integer column" do
+ @index.attributes[3].to_select_sql.should match(/|| ',' ||/)
+ end
+
+ it "should group with spaces if there's string columns from a has_many or has_and_belongs_to_many association" do
+ @index.attributes[4].to_select_sql.should match(/array_to_string\(array_accum\(.+, ' '\)/)
+ end
+
+ it "should group with commas if there's integer columns from a has_many or has_and_belongs_to_many association" do
+ @index.attributes[5].to_select_sql.should match(/array_to_string\(array_accum\(.+, ','\)/)
+ end
+ end
+
describe "to_group_sql method" do
before :each do
@attribute = ThinkingSphinx::Attribute.new([Object.stub_instance(:__stack => [])])
@@ -72,17 +120,237 @@
end
end
- describe '#initialize' do
- it 'raises if no columns are provided so that configuration errors are easier to track down' do
- lambda {
- ThinkingSphinx::Attribute.new([])
- }.should raise_error(RuntimeError)
+ describe "to_sphinx_clause method" do
+ before :each do
+ @attribute = ThinkingSphinx::Attribute.new [Object.stub_instance(:__stack => [])]
+ @attribute.stub_method(:unique_name => "unique name")
+ end
+
+ it "should use sql_attr_multi syntax for MVA attributes" do
+ @attribute.stub_method(:type => :multi)
+ @attribute.to_sphinx_clause.should match(/^sql_attr_multi\s+= uint unique name from field$/)
+ end
+
+ it "should use sql_attr_timestamp syntax for datetime values" do
+ @attribute.stub_method(:type => :datetime)
+ @attribute.to_sphinx_clause.should match(/^sql_attr_timestamp\s+= unique name$/)
+ end
+
+ it "should use sql_attr_str2ordinal for string values" do
+ @attribute.stub_method(:type => :string)
+ @attribute.to_sphinx_clause.should match(/^sql_attr_str2ordinal\s+= unique name$/)
end
+
+ it "should use sql_attr_float for float values" do
+ @attribute.stub_method(:type => :float)
+ @attribute.to_sphinx_clause.should match(/^sql_attr_float\s+= unique name$/)
+ end
+
+ it "should use sql_attr_bool for boolean values" do
+ @attribute.stub_method(:type => :boolean)
+ @attribute.to_sphinx_clause.should match(/^sql_attr_bool\s+= unique name$/)
+ end
+
+ it "should use sql_attr_uint for integer values" do
+ @attribute.stub_method(:type => :integer)
+ @attribute.to_sphinx_clause.should match(/^sql_attr_uint\s+= unique name$/)
+ end
+
+ it "should assume integer for any other types" do
+ @attribute.stub_method(:type => :unknown)
+ @attribute.to_sphinx_clause.should match(/^sql_attr_uint\s+= unique name$/)
+ end
+
+ end
+
+ describe "unique_name method" do
+ before :each do
+ @attribute = ThinkingSphinx::Attribute.new [
+ Object.stub_instance(:__stack => [], :__name => "col_name")
+ ]
+ end
+
+ it "should use the alias if there is one" do
+ @attribute.alias = "alias"
+ @attribute.unique_name.should == "alias"
+ end
+
+ it "should use the alias if there's multiple columns" do
+ @attribute.columns << Object.stub_instance(:__stack => [], :__name => "col_name")
+ @attribute.unique_name.should be_nil
+
+ @attribute.alias = "alias"
+ @attribute.unique_name.should == "alias"
+ end
+
+ it "should use the column name if there's no alias and just one column" do
+ @attribute.unique_name.should == "col_name"
+ end
+ end
+
+ describe "column_with_prefix method" do
+ before :each do
+ @attribute = ThinkingSphinx::Attribute.new [
+ ThinkingSphinx::Index::FauxColumn.new(:col_name)
+ ]
+ @attribute.columns.each { |col| @attribute.associations[col] = [] }
+ @attribute.model = Person
+
+ @first_join = Object.stub_instance(:aliased_table_name => "tabular")
+ @second_join = Object.stub_instance(:aliased_table_name => "data")
+
+ @first_assoc = ThinkingSphinx::Association.stub_instance(:join => @first_join)
+ @second_assoc = ThinkingSphinx::Association.stub_instance(:join => @second_join)
+ end
+
+ it "should return the column name if the column is a string" do
+ @attribute.columns = [ThinkingSphinx::Index::FauxColumn.new("string")]
+ @attribute.send(:column_with_prefix, @attribute.columns.first).should == "string"
+ end
+
+ it "should return the column with model's table prefix if there's no associations for the column" do
+ @attribute.send(:column_with_prefix, @attribute.columns.first).should == "`people`.`col_name`"
+ end
+
+ it "should return the column with its join table prefix if an association exists" do
+ column = @attribute.columns.first
+ @attribute.associations[column] = [@first_assoc]
+ @attribute.send(:column_with_prefix, column).should == "`tabular`.`col_name`"
+ end
+
+ it "should return multiple columns concatenated if more than one association exists" do
+ column = @attribute.columns.first
+ @attribute.associations[column] = [@first_assoc, @second_assoc]
+ @attribute.send(:column_with_prefix, column).should == "`tabular`.`col_name`, `data`.`col_name`"
+ end
+ end
+
+ describe "is_many? method" do
+ before :each do
+ @assoc_a = Object.stub_instance(:is_many? => true)
+ @assoc_b = Object.stub_instance(:is_many? => true)
+ @assoc_c = Object.stub_instance(:is_many? => true)
+
+ @attribute = ThinkingSphinx::Attribute.new(
+ [ThinkingSphinx::Index::FauxColumn.new(:col_name)]
+ )
+ @attribute.associations = {
+ :a => @assoc_a, :b => @assoc_b, :c => @assoc_c
+ }
+ end
+
+ it "should return true if all associations return true to is_many?" do
+ @attribute.send(:is_many?).should be_true
+ end
+
+ it "should return true if one association returns true to is_many?" do
+ @assoc_b.stub_method(:is_many? => false)
+ @assoc_c.stub_method(:is_many? => false)
+
+ @attribute.send(:is_many?).should be_true
+ end
+
+ it "should return false if all associations return false to is_many?" do
+ @assoc_a.stub_method(:is_many? => false)
+ @assoc_b.stub_method(:is_many? => false)
+ @assoc_c.stub_method(:is_many? => false)
+
+ @attribute.send(:is_many?).should be_false
+ end
+ end
+
+ describe "is_string? method" do
+ before :each do
+ @col_a = ThinkingSphinx::Index::FauxColumn.new("a")
+ @col_b = ThinkingSphinx::Index::FauxColumn.new("b")
+ @col_c = ThinkingSphinx::Index::FauxColumn.new("c")
- it 'raises if an element of the columns param is an integer - as happens when you use id instead of :id - so that configuration errors are easier to track down' do
- lambda {
- ThinkingSphinx::Attribute.new([1234])
- }.should raise_error(RuntimeError)
+ @attribute = ThinkingSphinx::Attribute.new(
+ [@col_a, @col_b, @col_c]
+ )
+ end
+
+ it "should return true if all columns return true to is_string?" do
+ @attribute.send(:is_string?).should be_true
+ end
+
+ it "should return false if one column returns true to is_string?" do
+ @col_a.send(:instance_variable_set, :@name, :a)
+ @attribute.send(:is_string?).should be_false
+ end
+
+ it "should return false if all columns return false to is_string?" do
+ @col_a.send(:instance_variable_set, :@name, :a)
+ @col_b.send(:instance_variable_set, :@name, :b)
+ @col_c.send(:instance_variable_set, :@name, :c)
+ @attribute.send(:is_string?).should be_false
+ end
+ end
+
+ describe "type method" do
+ before :each do
+ @column = ThinkingSphinx::Index::FauxColumn.new(:col_name)
+ @attribute = ThinkingSphinx::Attribute.new([@column])
+ @attribute.model = Person
+ @attribute.stub_method(:is_many? => false)
+ end
+
+ it "should return :multi if is_many? is true" do
+ @attribute.stub_method(:is_many? => true)
+ @attribute.send(:type).should == :multi
+ end
+
+ it "should return :string if there's more than one association" do
+ @attribute.associations = {:a => :assoc, :b => :assoc}
+ @attribute.send(:type).should == :string
+ end
+
+ it "should return the column type from the database if not :multi or more than one association" do
+ @column.send(:instance_variable_set, :@name, "birthday")
+ @attribute.send(:type).should == :datetime
+
+ @attribute.send(:instance_variable_set, :@type, nil)
+ @column.send(:instance_variable_set, :@name, "first_name")
+ @attribute.send(:type).should == :string
+
+ @attribute.send(:instance_variable_set, :@type, nil)
+ @column.send(:instance_variable_set, :@name, "id")
+ @attribute.send(:type).should == :integer
+ end
+ end
+
+ describe "all_ints? method" do
+ it "should return true if all columns are integers" do
+ attribute = ThinkingSphinx::Attribute.new(
+ [ ThinkingSphinx::Index::FauxColumn.new(:id),
+ ThinkingSphinx::Index::FauxColumn.new(:team_id) ]
+ )
+ attribute.model = Person
+ attribute.columns.each { |col| attribute.associations[col] = [] }
+
+ attribute.send(:all_ints?).should be_true
+ end
+
+ it "should return false if only some columns are integers" do
+ attribute = ThinkingSphinx::Attribute.new(
+ [ ThinkingSphinx::Index::FauxColumn.new(:id),
+ ThinkingSphinx::Index::FauxColumn.new(:first_name) ]
+ )
+ attribute.model = Person
+ attribute.columns.each { |col| attribute.associations[col] = [] }
+
+ attribute.send(:all_ints?).should be_false
+ end
+
+ it "should return false if no columns are integers" do
+ attribute = ThinkingSphinx::Attribute.new(
+ [ ThinkingSphinx::Index::FauxColumn.new(:first_name),
+ ThinkingSphinx::Index::FauxColumn.new(:last_name) ]
+ )
+ attribute.model = Person
+ attribute.columns.each { |col| attribute.associations[col] = [] }
+
+ attribute.send(:all_ints?).should be_false
end
end
end
View
80 spec/unit/thinking_sphinx/configuration_spec.rb
@@ -1,6 +1,44 @@
require 'spec/spec_helper'
describe ThinkingSphinx::Configuration do
+ describe "environment class method" do
+ before :each do
+ ThinkingSphinx::Configuration.send(:class_variable_set, :@@environment, nil)
+
+ ENV["RAILS_ENV"] = nil
+ ENV["MERB_ENV"] = nil
+ end
+
+ it "should use the Merb environment value if set" do
+ unless defined?(Merb)
+ module Merb; end
+ end
+
+ ThinkingSphinx::Configuration.stub_method(:defined? => true)
+ ENV["MERB_ENV"] = "merb_production"
+ ThinkingSphinx::Configuration.environment.should == "merb_production"
+
+ Object.send(:remove_const, :Merb)
+ end
+
+ it "should use the Rails environment value if set" do
+ ENV["RAILS_ENV"] = "rails_production"
+ ThinkingSphinx::Configuration.environment.should == "rails_production"
+ end
+
+ it "should default to development" do
+ ThinkingSphinx::Configuration.environment.should == "development"
+ end
+ end
+
+ describe "environment instance method" do
+ it "should return the class method" do
+ ThinkingSphinx::Configuration.stub_method(:environment => "spec")
+ ThinkingSphinx::Configuration.new.environment.should == "spec"
+ ThinkingSphinx::Configuration.should have_received(:environment)
+ end
+ end
+
describe "build method" do
before :each do
@config = ThinkingSphinx::Configuration.new
@@ -158,6 +196,44 @@
end
end
+ describe "load_models method" do
+ it "should have some specs"
+ end
+
+ describe "parse_config method" do
+ before :each do
+ @settings = {
+ "development" => {
+ "config_file" => "my_conf_file.conf",
+ "searchd_log_file" => "searchd_log_file.log",
+ "query_log_file" => "query_log_file.log",
+ "pid_file" => "pid_file.pid",
+ "searchd_file_path" => "searchd/file/path",
+ "address" => "127.0.0.1",
+ "port" => 3333,
+ "allow_star" => true,
+ "mem_limit" => "128M",
+ "max_matches" => 1001,
+ "morphology" => "stem_ru",
+ "charset_type" => "latin1",
+ "charset_table" => "table",
+ "ignore_chars" => "e"
+ }
+ }
+ # puts YAML.dump(settings)
+ open("#{RAILS_ROOT}/config/sphinx.yml", "w") do |f|
+ f.write YAML.dump(@settings)
+ end
+ end
+
+ it "should use the accessors to set the configuration values" do
+ config = ThinkingSphinx::Configuration.new
+ @settings["development"].each do |key, value|
+ config.send(key).should == value
+ end
+ end
+ end
+
describe "core_index_for_model method" do
before :each do
@config = ThinkingSphinx::Configuration.new
@@ -355,4 +431,8 @@
)
end
end
+
+ describe "create_array_accum method" do
+ it "should create the array_accum method on PostgreSQL"
+ end
end
View
153 spec/unit/thinking_sphinx/field_spec.rb
@@ -1,7 +1,21 @@
require 'spec/spec_helper'
describe ThinkingSphinx::Field do
- describe "to_select_sql method" do
+ describe '#initialize' do
+ it 'raises if no columns are provided so that configuration errors are easier to track down' do
+ lambda {
+ ThinkingSphinx::Field.new([])
+ }.should raise_error(RuntimeError)
+ end
+
+ it 'raises if an element of the columns param is an integer - as happens when you use id instead of :id - so that configuration errors are easier to track down' do
+ lambda {
+ ThinkingSphinx::Field.new([1234])
+ }.should raise_error(RuntimeError)
+ end
+ end
+
+ describe "to_select_sql method with MySQL" do
before :each do
@index = Person.indexes.first
@index.link!
@@ -20,6 +34,28 @@
end
end
+ describe "to_select_sql method with PostgreSQL" do
+ before :each do
+ @index = Person.indexes.first
+ Person.connection.class.stub_method(
+ :name => "ActiveRecord::ConnectionAdapters::PostgreSQLAdapter"
+ )
+ @index.link!
+ end
+
+ it "should concat with spaces if there are multiple columns" do
+ @index.fields.first.to_select_sql.should match(/|| ' ' ||/)
+ end
+
+ it "should concat with spaces if a column has more than one association" do
+ @index.fields[1].to_select_sql.should match(/|| ' ' ||/)
+ end
+
+ it "should group if any association for any column is a has_many or has_and_belongs_to_many" do
+ @index.fields[2].to_select_sql.should match(/array_to_string\(array_accum\(/)
+ end
+ end
+
describe "to_group_sql method" do
before :each do
@field = ThinkingSphinx::Field.new([Object.stub_instance(:__stack => [])])
@@ -44,26 +80,33 @@
@field.stub_method(:column_with_prefix => 'hello')
@field.to_group_sql.should be_a_kind_of(Array)
end
+ end
+
+ describe "unique_name method" do
+ before :each do
+ @field = ThinkingSphinx::Field.new [
+ Object.stub_instance(:__stack => [], :__name => "col_name")
+ ]
+ end
- after :each do
- ThinkingSphinx.unstub_method(:use_group_by_shortcut?)
+ it "should use the alias if there is one" do
+ @field.alias = "alias"
+ @field.unique_name.should == "alias"
end
- end
-
- describe '#initialize' do
- it 'raises if no columns are provided so that configuration errors are easier to track down' do
- lambda {
- ThinkingSphinx::Field.new([])
- }.should raise_error(RuntimeError)
+
+ it "should use the alias if there's multiple columns" do
+ @field.columns << Object.stub_instance(:__stack => [], :__name => "col_name")
+ @field.unique_name.should be_nil
+
+ @field.alias = "alias"
+ @field.unique_name.should == "alias"
end
-
- it 'raises if an element of the columns param is an integer - as happens when you use id instead of :id - so that configuration errors are easier to track down' do
- lambda {
- ThinkingSphinx::Field.new([1234])
- }.should raise_error(RuntimeError)
+
+ it "should use the column name if there's no alias and just one column" do
+ @field.unique_name.should == "col_name"
end
end
-
+
describe "prefixes method" do
it "should default to false" do
@field = ThinkingSphinx::Field.new([Object.stub_instance(:__stack => [])])
@@ -91,4 +134,82 @@
@field.infixes.should be_true
end
end
+
+ describe "quote_column_name method" do
+ it "should delegate the call to the model's connection" do
+ @field = ThinkingSphinx::Field.new [
+ ThinkingSphinx::Index::FauxColumn.new(:col_name)
+ ]
+ @field.model = Person
+ Person.connection.stub_method(:quote_column_name => "quoted!")
+
+ @field.send(:quote_column, "blah").should == "quoted!"
+ end
+ end
+
+ describe "column_with_prefix method" do
+ before :each do
+ @field = ThinkingSphinx::Field.new [
+ ThinkingSphinx::Index::FauxColumn.new(:col_name)
+ ]
+ @field.columns.each { |col| @field.associations[col] = [] }
+ @field.model = Person
+
+ @first_join = Object.stub_instance(:aliased_table_name => "tabular")
+ @second_join = Object.stub_instance(:aliased_table_name => "data")
+
+ @first_assoc = ThinkingSphinx::Association.stub_instance(:join => @first_join)
+ @second_assoc = ThinkingSphinx::Association.stub_instance(:join => @second_join)
+ end
+
+ it "should return the column with model's table prefix if there's no associations for the column" do
+ @field.send(:column_with_prefix, @field.columns.first).should == "`people`.`col_name`"
+ end
+
+ it "should return the column with its join table prefix if an association exists" do
+ column = @field.columns.first
+ @field.associations[column] = [@first_assoc]
+ @field.send(:column_with_prefix, column).should == "`tabular`.`col_name`"
+ end
+
+ it "should return multiple columns concatenated if more than one association exists" do
+ column = @field.columns.first
+ @field.associations[column] = [@first_assoc, @second_assoc]
+ @field.send(:column_with_prefix, column).should == "`tabular`.`col_name`, `data`.`col_name`"
+ end
+ end
+
+ describe "is_many? method" do
+ before :each do
+ @assoc_a = Object.stub_instance(:is_many? => true)
+ @assoc_b = Object.stub_instance(:is_many? => true)
+ @assoc_c = Object.stub_instance(:is_many? => true)
+
+ @field = ThinkingSphinx::Field.new(
+ [ThinkingSphinx::Index::FauxColumn.new(:col_name)]
+ )
+ @field.associations = {
+ :a => @assoc_a, :b => @assoc_b, :c => @assoc_c
+ }
+ end
+
+ it "should return true if all associations return true to is_many?" do
+ @field.send(:is_many?).should be_true
+ end
+
+ it "should return true if one association returns true to is_many?" do
+ @assoc_b.stub_method(:is_many? => false)
+ @assoc_c.stub_method(:is_many? => false)
+
+ @field.send(:is_many?).should be_true
+ end
+
+ it "should return false if all associations return false to is_many?" do
+ @assoc_a.stub_method(:is_many? => false)
+ @assoc_b.stub_method(:is_many? => false)
+ @assoc_c.stub_method(:is_many? => false)
+
+ @field.send(:is_many?).should be_false
+ end
+ end
end
View
25 spec/unit/thinking_sphinx_spec.rb
@@ -78,5 +78,30 @@
ThinkingSphinx.use_group_by_shortcut?.should be_false
end
+
+ describe "if not using MySQL" do
+ before :each do
+ @connection = ::ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.stub_instance(
+ :select_all => true
+ )
+ ::ActiveRecord::Base.stub_method(
+ :connection => @connection
+ )
+ end
+
+ after :each do
+ ::ActiveRecord::Base.unstub_method(:connection)
+ end
+
+ it "should return false" do
+ ThinkingSphinx.use_group_by_shortcut?.should be_false
+ end
+
+ it "should not call select_all" do
+ ThinkingSphinx.use_group_by_shortcut?
+
+ @connection.should_not have_received(:select_all)
+ end
+ end
end
end
View
2  thinking-sphinx.gemspec
@@ -1,6 +1,6 @@
Gem::Specification.new do |s|
s.name = "thinking-sphinx"
- s.version = "0.9.6"
+ s.version = "0.9.7"
s.summary = "A concise and easy-to-use Ruby library that connects ActiveRecord to the Sphinx search daemon, managing configuration, indexing and searching."
s.description = "A concise and easy-to-use Ruby library that connects ActiveRecord to the Sphinx search daemon, managing configuration, indexing and searching."
s.author = "Pat Allan"
Please sign in to comment.
Something went wrong with that request. Please try again.