require File.dirname(__FILE__) + '/../spec_helper' require 'database_cleaner/active_record/transaction' require 'database_cleaner/data_mapper/transaction' require 'database_cleaner/mongo_mapper/truncation' require 'database_cleaner/mongoid/truncation' require 'database_cleaner/couch_potato/truncation' require 'database_cleaner/neo4j/transaction' module DatabaseCleaner describe Base do let(:mock_strategy) { double("strategy").tap{|strategy| strategy.stub(:to_ary => [strategy]) } } describe "autodetect" do #Cache all ORMs, we'll need them later but not now. before(:all) do Temp_AR = ::ActiveRecord if defined?(::ActiveRecord) and not defined?(Temp_AR) Temp_DM = ::DataMapper if defined?(::DataMapper) and not defined?(Temp_DM) Temp_MM = ::MongoMapper if defined?(::MongoMapper) and not defined?(Temp_MM) Temp_MO = ::Mongoid if defined?(::Mongoid) and not defined?(Temp_MO) Temp_CP = ::CouchPotato if defined?(::CouchPotato) and not defined?(Temp_CP) Temp_SQ = ::Sequel if defined?(::Sequel) and not defined?(Temp_SQ) Temp_MP = ::Moped if defined?(::Moped) and not defined?(Temp_MP) Temp_RS = ::Redis if defined?(::Redis) and not defined?(Temp_RS) Temp_OH = ::Ohm if defined?(::Ohm) and not defined?(Temp_OH) Temp_NJ = ::Neo4j if defined?(::Neo4j) and not defined?(Temp_NJ) end #Remove all ORM mocks and restore from cache after(:all) do Object.send(:remove_const, 'ActiveRecord') if defined?(::ActiveRecord) Object.send(:remove_const, 'DataMapper') if defined?(::DataMapper) Object.send(:remove_const, 'MongoMapper') if defined?(::MongoMapper) Object.send(:remove_const, 'Mongoid') if defined?(::Mongoid) Object.send(:remove_const, 'CouchPotato') if defined?(::CouchPotato) Object.send(:remove_const, 'Sequel') if defined?(::Sequel) Object.send(:remove_const, 'Moped') if defined?(::Moped) Object.send(:remove_const, 'Ohm') if defined?(::Ohm) Object.send(:remove_const, 'Redis') if defined?(::Redis) Object.send(:remove_const, 'Neo4j') if defined?(::Neo4j) # Restore ORMs ::ActiveRecord = Temp_AR if defined? Temp_AR ::DataMapper = Temp_DM if defined? Temp_DM ::MongoMapper = Temp_MM if defined? Temp_MM ::Mongoid = Temp_MO if defined? Temp_MO ::CouchPotato = Temp_CP if defined? Temp_CP ::Sequel = Temp_SQ if defined? Temp_SQ ::Moped = Temp_MP if defined? Temp_MP ::Ohm = Temp_OH if defined? Temp_OH ::Redis = Temp_RS if defined? Temp_RS ::Neo4j = Temp_NJ if defined? Temp_NJ end #reset the orm mocks before(:each) do Object.send(:remove_const, 'ActiveRecord') if defined?(::ActiveRecord) Object.send(:remove_const, 'DataMapper') if defined?(::DataMapper) Object.send(:remove_const, 'MongoMapper') if defined?(::MongoMapper) Object.send(:remove_const, 'Mongoid') if defined?(::Mongoid) Object.send(:remove_const, 'CouchPotato') if defined?(::CouchPotato) Object.send(:remove_const, 'Sequel') if defined?(::Sequel) Object.send(:remove_const, 'Moped') if defined?(::Moped) Object.send(:remove_const, 'Ohm') if defined?(::Ohm) Object.send(:remove_const, 'Redis') if defined?(::Redis) Object.send(:remove_const, 'Neo4j') if defined?(::Neo4j) end let(:cleaner) { DatabaseCleaner::Base.new :autodetect } it "should raise an error when no ORM is detected" do running { cleaner }.should raise_error(DatabaseCleaner::NoORMDetected) end it "should detect ActiveRecord first" do Object.const_set('ActiveRecord','Actively mocking records.') Object.const_set('DataMapper', 'Mapping data mocks') Object.const_set('MongoMapper', 'Mapping mock mongos') Object.const_set('Mongoid', 'Mongoid mock') Object.const_set('CouchPotato', 'Couching mock potatos') Object.const_set('Sequel', 'Sequel mock') Object.const_set('Moped', 'Moped mock') Object.const_set('Ohm', 'Ohm mock') Object.const_set('Redis', 'Redis mock') Object.const_set('Neo4j', 'Neo4j mock') cleaner.orm.should eq :active_record cleaner.should be_auto_detected end it "should detect DataMapper second" do Object.const_set('DataMapper', 'Mapping data mocks') Object.const_set('MongoMapper', 'Mapping mock mongos') Object.const_set('Mongoid', 'Mongoid mock') Object.const_set('CouchPotato', 'Couching mock potatos') Object.const_set('Sequel', 'Sequel mock') Object.const_set('Moped', 'Moped mock') Object.const_set('Ohm', 'Ohm mock') Object.const_set('Redis', 'Redis mock') Object.const_set('Neo4j', 'Neo4j mock') cleaner.orm.should eq :data_mapper cleaner.should be_auto_detected end it "should detect MongoMapper third" do Object.const_set('MongoMapper', 'Mapping mock mongos') Object.const_set('Mongoid', 'Mongoid mock') Object.const_set('CouchPotato', 'Couching mock potatos') Object.const_set('Sequel', 'Sequel mock') Object.const_set('Moped', 'Moped mock') Object.const_set('Ohm', 'Ohm mock') Object.const_set('Redis', 'Redis mock') Object.const_set('Neo4j', 'Neo4j mock') cleaner.orm.should eq :mongo_mapper cleaner.should be_auto_detected end it "should detect Mongoid fourth" do Object.const_set('Mongoid', 'Mongoid mock') Object.const_set('CouchPotato', 'Couching mock potatos') Object.const_set('Sequel', 'Sequel mock') Object.const_set('Moped', 'Moped mock') Object.const_set('Ohm', 'Ohm mock') Object.const_set('Redis', 'Redis mock') Object.const_set('Neo4j', 'Neo4j mock') cleaner.orm.should eq :mongoid cleaner.should be_auto_detected end it "should detect CouchPotato fifth" do Object.const_set('CouchPotato', 'Couching mock potatos') Object.const_set('Sequel', 'Sequel mock') Object.const_set('Moped', 'Moped mock') Object.const_set('Ohm', 'Ohm mock') Object.const_set('Redis', 'Redis mock') Object.const_set('Neo4j', 'Neo4j mock') cleaner.orm.should eq :couch_potato cleaner.should be_auto_detected end it "should detect Sequel sixth" do Object.const_set('Sequel', 'Sequel mock') Object.const_set('Moped', 'Moped mock') Object.const_set('Ohm', 'Ohm mock') Object.const_set('Redis', 'Redis mock') Object.const_set('Neo4j', 'Neo4j mock') cleaner.orm.should eq :sequel cleaner.should be_auto_detected end it 'detects Moped seventh' do Object.const_set('Moped', 'Moped mock') cleaner.orm.should eq :moped cleaner.should be_auto_detected end it 'detects Ohm eighth' do Object.const_set('Ohm', 'Ohm mock') Object.const_set('Redis', 'Redis mock') Object.const_set('Neo4j', 'Neo4j mock') cleaner.orm.should eq :ohm cleaner.should be_auto_detected end it 'detects Redis ninth' do Object.const_set('Redis', 'Redis mock') Object.const_set('Neo4j', 'Neo4j mock') cleaner.orm.should eq :redis cleaner.should be_auto_detected end it 'detects Neo4j tenth' do Object.const_set('Neo4j', 'Neo4j mock') cleaner.orm.should eq :neo4j cleaner.should be_auto_detected end end describe "orm_module" do it "should ask ::DatabaseCleaner what the module is for its orm" do orm = double("orm") mockule = double("module") cleaner = ::DatabaseCleaner::Base.new cleaner.should_receive(:orm).and_return(orm) ::DatabaseCleaner.should_receive(:orm_module).with(orm).and_return(mockule) cleaner.send(:orm_module).should eq mockule end end describe "comparison" do it "should be equal if orm, connection and strategy are the same" do one = DatabaseCleaner::Base.new(:active_record,:connection => :default) one.strategy = mock_strategy two = DatabaseCleaner::Base.new(:active_record,:connection => :default) two.strategy = mock_strategy one.should eq two two.should eq one end it "should not be equal if orm are not the same" do one = DatabaseCleaner::Base.new(:mongo_id, :connection => :default) one.strategy = mock_strategy two = DatabaseCleaner::Base.new(:active_record, :connection => :default) two.strategy = mock_strategy one.should_not eq two two.should_not eq one end it "should not be equal if connection are not the same" do one = DatabaseCleaner::Base.new(:active_record, :connection => :default) one.strategy = :truncation two = DatabaseCleaner::Base.new(:active_record, :connection => :other) two.strategy = :truncation one.should_not eq two two.should_not eq one end end describe "initialization" do context "db specified" do subject { ::DatabaseCleaner::Base.new(:active_record,:connection => :my_db) } it "should store db from :connection in params hash" do subject.db.should eq :my_db end end describe "orm" do it "should store orm" do cleaner = ::DatabaseCleaner::Base.new :a_orm cleaner.orm.should eq :a_orm end it "converts string to symbols" do cleaner = ::DatabaseCleaner::Base.new "mongoid" cleaner.orm.should eq :mongoid end it "is autodetected if orm is not provided" do cleaner = ::DatabaseCleaner::Base.new cleaner.should be_auto_detected end it "is autodetected if you specify :autodetect" do cleaner = ::DatabaseCleaner::Base.new "autodetect" cleaner.should be_auto_detected end it "should default to autodetect upon initalisation" do subject.should be_auto_detected end end end describe "db" do it "should default to :default" do subject.db.should eq :default end it "should return any stored db value" do subject.stub(:strategy_db=) subject.db = :test_db subject.db.should eq :test_db end it "should pass db to any specified strategy" do subject.should_receive(:strategy_db=).with(:a_new_db) subject.db = :a_new_db end end describe "strategy_db=" do let(:strategy) { mock_strategy } before(:each) do subject.strategy = strategy end it "should check that strategy supports db specification" do strategy.should_receive(:respond_to?).with(:db=).and_return(true) strategy.stub(:db=) subject.strategy_db = :a_db end context "when strategy supports db specification" do before(:each) { strategy.stub(:respond_to?).with(:db=).and_return true } it "should pass db to the strategy" do strategy.should_receive(:db=).with(:a_db) subject.strategy_db = :a_db end end context "when strategy doesn't supports db specification" do before(:each) { strategy.stub(:respond_to?).with(:db=).and_return false } it "should check to see if db is :default" do db = double("default") db.should_receive(:==).with(:default).and_return(true) subject.strategy_db = db end it "should raise an argument error when db isn't default" do db = double("a db") expect{ subject.strategy_db = db }.to raise_error ArgumentError end end end describe "clean_with" do let (:strategy) { double("strategy",:clean => true) } before(:each) { subject.stub(:create_strategy).with(anything).and_return(strategy) } it "should pass all arguments to create_strategy" do subject.should_receive(:create_strategy).with(:lorum, :dollar, :amet, :ipsum => "random").and_return(strategy) subject.clean_with :lorum, :dollar, :amet, { :ipsum => "random" } end it "should invoke clean on the created strategy" do strategy.should_receive(:clean) subject.clean_with :strategy end it "should return the strategy" do subject.clean_with( :strategy ).should eq strategy end end describe "clean_with!" do let (:strategy) { double("strategy",:clean => true) } before(:each) { subject.stub(:create_strategy).with(anything).and_return(strategy) } it "should pass all arguments to create_strategy" do subject.should_receive(:create_strategy).with(:lorum, :dollar, :amet, :ipsum => "random").and_return(strategy) subject.clean_with! :lorum, :dollar, :amet, { :ipsum => "random" } end it "should invoke clean on the created strategy" do strategy.should_receive(:clean) subject.clean_with! :strategy end it "should return the strategy" do subject.clean_with!( :strategy ).should eq strategy end end describe "create_strategy" do let(:strategy_class) { double("strategy_class",:new => double("instance")) } before :each do subject.stub(:orm_strategy).and_return(strategy_class) end it "should pass the first argument to orm_strategy" do subject.should_receive(:orm_strategy).with(:strategy).and_return(Object) subject.create_strategy :strategy end it "should pass the remainding argument to orm_strategy.new" do strategy_class.should_receive(:new).with(:params => {:lorum => "ipsum"}) subject.create_strategy :strategy, {:params => {:lorum => "ipsum"}} end it "should return the resulting strategy" do subject.create_strategy( :strategy ).should eq strategy_class.new end end describe "strategy=" do it "should proxy symbolised strategies to create_strategy" do subject.should_receive(:create_strategy).with(:symbol) subject.strategy = :symbol end it "should proxy params with symbolised strategies" do subject.should_receive(:create_strategy).with(:symbol,:param => "one") subject.strategy= :symbol, {:param => "one"} end it "should accept strategy objects" do expect{ subject.strategy = mock_strategy }.to_not raise_error end it "should raise argument error when params given with strategy Object" do expect{ subject.strategy = double("object"), {:param => "one"} }.to raise_error ArgumentError end it "should attempt to set strategy db" do subject.stub(:db).and_return(:my_db) subject.should_receive(:set_strategy_db).with(mock_strategy, :my_db) subject.strategy = mock_strategy end it "should return the stored strategy" do result = subject.strategy = mock_strategy result.should eq mock_strategy end end describe "strategy" do subject { ::DatabaseCleaner::Base.new :a_orm } it "returns a null strategy when strategy is not set and undetectable" do subject.strategy.should eq DatabaseCleaner::NullStrategy end it "returns the set strategy" do subject.strategy = mock_strategy subject.strategy.should eq mock_strategy end end describe "orm=" do it "should stored the desired orm" do subject.orm.should_not eq :desired_orm subject.orm = :desired_orm subject.orm.should eq :desired_orm end end describe "orm" do let(:mock_orm) { double("orm") } it "should return orm if orm set" do subject.instance_variable_set "@orm", mock_orm subject.orm.should eq mock_orm end context "orm isn't set" do before(:each) { subject.instance_variable_set "@orm", nil } it "should run autodetect if orm isn't set" do subject.should_receive(:autodetect) subject.orm end it "should return the result of autodetect if orm isn't set" do subject.stub(:autodetect).and_return(mock_orm) subject.orm.should eq mock_orm end end end describe "proxy methods" do let (:strategy) { double("strategy") } before(:each) do subject.stub(:strategy).and_return(strategy) end describe "start" do it "should proxy start to the strategy" do strategy.should_receive(:start) subject.start end end describe "clean" do it "should proxy clean to the strategy" do strategy.should_receive(:clean) subject.clean end end describe "clean!" do it "should proxy clean! to the strategy clean" do strategy.should_receive(:clean) subject.clean! end end describe "cleaning" do it "should proxy cleaning to the strategy" do strategy.should_receive(:cleaning) subject.cleaning { } end end end describe "auto_detected?" do it "should return true unless @autodetected is nil" do subject.instance_variable_set("@autodetected","not nil") subject.auto_detected?.should be_true end it "should return false if @autodetect is nil" do subject.instance_variable_set("@autodetected",nil) subject.auto_detected?.should be_false end end describe "orm_strategy" do let (:strategy_class) { double("strategy_class") } before(:each) do subject.stub(:orm_module).and_return(strategy_class) end context "in response to a LoadError" do before(:each) { subject.should_receive(:require).with(anything).and_raise(LoadError) } it "should raise UnknownStrategySpecified" do expect { subject.send(:orm_strategy,:a_strategy) }.to raise_error UnknownStrategySpecified end it "should ask orm_module if it will list available_strategies" do strategy_class.should_receive(:respond_to?).with(:available_strategies) subject.stub(:orm_module).and_return(strategy_class) expect { subject.send(:orm_strategy,:a_strategy) }.to raise_error UnknownStrategySpecified end it "should use available_strategies (for the error message) if its available" do strategy_class.stub(:respond_to?).with(:available_strategies).and_return(true) strategy_class.should_receive(:available_strategies).and_return([]) subject.stub(:orm_module).and_return(strategy_class) expect { subject.send(:orm_strategy,:a_strategy) }.to raise_error UnknownStrategySpecified end end it "should return the constant of the Strategy class requested" do strategy_strategy_class = double("strategy strategy_class") subject.stub(:require).with(anything).and_return(true) strategy_class.should_receive(:const_get).with("Cunningplan").and_return(strategy_strategy_class) subject.send(:orm_strategy, :cunningplan).should eq strategy_strategy_class end end describe 'set_default_orm_strategy' do it 'sets strategy to :transaction for ActiveRecord' do cleaner = DatabaseCleaner::Base.new(:active_record) cleaner.strategy.should be_instance_of DatabaseCleaner::ActiveRecord::Transaction end it 'sets strategy to :transaction for DataMapper' do cleaner = DatabaseCleaner::Base.new(:data_mapper) cleaner.strategy.should be_instance_of DatabaseCleaner::DataMapper::Transaction end it 'sets strategy to :truncation for MongoMapper' do cleaner = DatabaseCleaner::Base.new(:mongo_mapper) cleaner.strategy.should be_instance_of DatabaseCleaner::MongoMapper::Truncation end it 'sets strategy to :truncation for Mongoid' do cleaner = DatabaseCleaner::Base.new(:mongoid) cleaner.strategy.should be_instance_of DatabaseCleaner::Mongoid::Truncation end it 'sets strategy to :truncation for CouchPotato' do cleaner = DatabaseCleaner::Base.new(:couch_potato) cleaner.strategy.should be_instance_of DatabaseCleaner::CouchPotato::Truncation end it 'sets strategy to :transaction for Sequel' do cleaner = DatabaseCleaner::Base.new(:sequel) cleaner.strategy.should be_instance_of DatabaseCleaner::Sequel::Transaction end it 'sets strategy to :truncation for Moped' do cleaner = DatabaseCleaner::Base.new(:moped) cleaner.strategy.should be_instance_of DatabaseCleaner::Moped::Truncation end it 'sets strategy to :truncation for Ohm' do cleaner = DatabaseCleaner::Base.new(:ohm) cleaner.strategy.should be_instance_of DatabaseCleaner::Ohm::Truncation end it 'sets strategy to :truncation for Redis' do cleaner = DatabaseCleaner::Base.new(:redis) cleaner.strategy.should be_instance_of DatabaseCleaner::Redis::Truncation end it 'sets strategy to :transaction for Neo4j' do cleaner = DatabaseCleaner::Base.new(:neo4j) cleaner.strategy.should be_instance_of DatabaseCleaner::Neo4j::Transaction end end end end