nulldb 0.3.7.pre.alpha.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +28 -0
  3. data/.travis.yml +49 -0
  4. data/Appraisals +36 -0
  5. data/CHANGES.md +75 -0
  6. data/Gemfile +14 -0
  7. data/LICENSE +21 -0
  8. data/README.rdoc +147 -0
  9. data/Rakefile +14 -0
  10. data/VERSION +1 -0
  11. data/gemfiles/activerecord_2.3.gemfile +17 -0
  12. data/gemfiles/activerecord_3.0.gemfile +16 -0
  13. data/gemfiles/activerecord_3.1.gemfile +16 -0
  14. data/gemfiles/activerecord_3.2.gemfile +16 -0
  15. data/gemfiles/activerecord_4.0.gemfile +16 -0
  16. data/gemfiles/activerecord_4.1.gemfile +16 -0
  17. data/gemfiles/activerecord_4.2.gemfile +16 -0
  18. data/gemfiles/activerecord_5.0.gemfile +16 -0
  19. data/gemfiles/activerecord_5.1.gemfile +16 -0
  20. data/gemfiles/activerecord_master.gemfile +18 -0
  21. data/lib/active_record/connection_adapters/nulldb_adapter.rb +21 -0
  22. data/lib/active_record/connection_adapters/nulldb_adapter/checkpoint.rb +13 -0
  23. data/lib/active_record/connection_adapters/nulldb_adapter/column.rb +20 -0
  24. data/lib/active_record/connection_adapters/nulldb_adapter/configuration.rb +5 -0
  25. data/lib/active_record/connection_adapters/nulldb_adapter/core.rb +324 -0
  26. data/lib/active_record/connection_adapters/nulldb_adapter/empty_result.rb +26 -0
  27. data/lib/active_record/connection_adapters/nulldb_adapter/index_definition.rb +5 -0
  28. data/lib/active_record/connection_adapters/nulldb_adapter/null_object.rb +13 -0
  29. data/lib/active_record/connection_adapters/nulldb_adapter/statement.rb +15 -0
  30. data/lib/active_record/connection_adapters/nulldb_adapter/table_definition.rb +5 -0
  31. data/lib/activerecord-nulldb-adapter.rb +1 -0
  32. data/lib/nulldb.rb +2 -0
  33. data/lib/nulldb/arel_compiler.rb +6 -0
  34. data/lib/nulldb/core.rb +39 -0
  35. data/lib/nulldb/extensions.rb +42 -0
  36. data/lib/nulldb/rails.rb +4 -0
  37. data/lib/nulldb_rspec.rb +104 -0
  38. data/lib/tasks/database.rake +32 -0
  39. data/nulldb.gemspec +27 -0
  40. data/spec/nulldb_spec.rb +345 -0
  41. data/spec/spec.opts +1 -0
  42. metadata +172 -0
@@ -0,0 +1,26 @@
1
+ class ActiveRecord::ConnectionAdapters::NullDBAdapter
2
+
3
+ class EmptyResult < Array
4
+ attr_writer :columns
5
+ def rows
6
+ []
7
+ end
8
+
9
+ def column_types
10
+ columns.map{|col| col.type}
11
+ end
12
+
13
+ def columns
14
+ @columns ||= []
15
+ end
16
+
17
+ def cast_values(type_overrides = nil)
18
+ rows
19
+ end
20
+
21
+ def >(num)
22
+ rows.size > num
23
+ end
24
+ end
25
+
26
+ end
@@ -0,0 +1,5 @@
1
+ class ActiveRecord::ConnectionAdapters::NullDBAdapter
2
+
3
+ class IndexDefinition < Struct.new(:table, :name, :unique, :columns, :lengths, :orders); end
4
+
5
+ end
@@ -0,0 +1,13 @@
1
+ class ActiveRecord::ConnectionAdapters::NullDBAdapter
2
+
3
+ class NullObject
4
+ def method_missing(*args, &block)
5
+ nil
6
+ end
7
+
8
+ def to_a
9
+ []
10
+ end
11
+ end
12
+
13
+ end
@@ -0,0 +1,15 @@
1
+ class ActiveRecord::ConnectionAdapters::NullDBAdapter
2
+
3
+ class Statement
4
+ attr_reader :entry_point, :content
5
+
6
+ def initialize(entry_point, content = "")
7
+ @entry_point, @content = entry_point, content
8
+ end
9
+
10
+ def ==(other)
11
+ self.entry_point == other.entry_point
12
+ end
13
+ end
14
+
15
+ end
@@ -0,0 +1,5 @@
1
+ class ActiveRecord::ConnectionAdapters::NullDBAdapter
2
+
3
+ TableDefinition = ActiveRecord::ConnectionAdapters::TableDefinition
4
+
5
+ end
@@ -0,0 +1 @@
1
+ require 'nulldb'
@@ -0,0 +1,2 @@
1
+ require 'nulldb/core'
2
+ require 'nulldb/rails'
@@ -0,0 +1,6 @@
1
+ module Arel
2
+ module SqlCompiler
3
+ class NullDBCompiler < GenericCompiler
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,39 @@
1
+ require 'active_support'
2
+ require 'active_support/deprecation'
3
+ require 'active_record/connection_adapters/nulldb_adapter'
4
+
5
+ module NullDB
6
+ class Configuration < Struct.new(:project_root); end
7
+
8
+ class << self
9
+ def configure
10
+ @configuration = Configuration.new.tap {|c| yield c}
11
+ end
12
+
13
+ def configuration
14
+ if @configuration.nil?
15
+ raise "NullDB not configured. Require a framework, ex 'nulldb/rails'"
16
+ end
17
+
18
+ @configuration
19
+ end
20
+
21
+ def nullify(options={})
22
+ begin
23
+ @prev_connection = ActiveRecord::Base.connection_pool.try(:spec)
24
+ rescue ActiveRecord::ConnectionNotEstablished
25
+ end
26
+ ActiveRecord::Base.establish_connection(options.merge(:adapter => :nulldb))
27
+ end
28
+
29
+ def restore
30
+ if @prev_connection
31
+ ActiveRecord::Base.establish_connection(@prev_connection.config)
32
+ end
33
+ end
34
+
35
+ def checkpoint
36
+ ActiveRecord::Base.connection.checkpoint!
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,42 @@
1
+ unless respond_to?(:tap)
2
+ class Object
3
+ def tap
4
+ yield self
5
+ self
6
+ end
7
+ end
8
+ end
9
+
10
+ unless respond_to?(:try)
11
+ class Object
12
+ def try(*a, &b)
13
+ if a.empty? && block_given?
14
+ yield self
15
+ else
16
+ __send__(*a, &b)
17
+ end
18
+ end
19
+ end
20
+
21
+ class NilClass
22
+ def try(*args); nil; end
23
+ end
24
+ end
25
+
26
+ class ActiveRecord::Base
27
+ # Instantiate a new NullDB connection. Used by ActiveRecord internally.
28
+ def self.nulldb_connection(config)
29
+ ActiveRecord::ConnectionAdapters::NullDBAdapter.new(config)
30
+ end
31
+ end
32
+
33
+
34
+ module ActiveRecord
35
+ # Just make sure you have the latest version of your schema
36
+ superclass = ActiveRecord::VERSION::MAJOR == 5 ? Migration.public_send(:[], "#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}".to_f) : Migration
37
+ class Schema < superclass
38
+ def self.define(info={}, &block)
39
+ instance_eval(&block)
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,4 @@
1
+ require 'nulldb/core'
2
+
3
+ # Need to defer calling Rails.root because when bundler loads, Rails.root is nil
4
+ NullDB.configure {|ndb| def ndb.project_root;Rails.root;end}
@@ -0,0 +1,104 @@
1
+ require 'active_record/connection_adapters/nulldb_adapter'
2
+
3
+ module NullDB
4
+ module RSpec
5
+ end
6
+ end
7
+
8
+ module NullDB::RSpec::NullifiedDatabase
9
+ NullDBAdapter = ActiveRecord::ConnectionAdapters::NullDBAdapter
10
+
11
+ class HaveExecuted
12
+
13
+ def initialize(entry_point)
14
+ @entry_point = entry_point
15
+ end
16
+
17
+ def matches?(connection)
18
+ log = connection.execution_log_since_checkpoint
19
+ if @entry_point == :anything
20
+ not log.empty?
21
+ else
22
+ log.include?(NullDBAdapter::Statement.new(@entry_point))
23
+ end
24
+ end
25
+
26
+ def description
27
+ "connection should execute #{@entry_point} statement"
28
+ end
29
+
30
+ def failure_message
31
+ " did not execute #{@entry_point} statement when it should have"
32
+ end
33
+
34
+ def negative_failure_message
35
+ " executed #{@entry_point} statement when it should not have"
36
+ end
37
+ end
38
+
39
+ def self.globally_nullify_database
40
+ block = lambda { |config| nullify_database(config) }
41
+ if defined?(RSpec)
42
+ RSpec.configure(&block)
43
+ else
44
+ Spec::Runner.configure(&block)
45
+ end
46
+ end
47
+
48
+ def self.contextually_nullify_database(context)
49
+ nullify_database(context)
50
+ end
51
+
52
+ # A matcher for asserting that database statements have (or have not) been
53
+ # executed. Usage:
54
+ #
55
+ # ActiveRecord::Base.connection.should have_executed(:insert)
56
+ #
57
+ # The types of statement that can be matched mostly mirror the public
58
+ # operations available in
59
+ # ActiveRecord::ConnectionAdapters::DatabaseStatements:
60
+ # - :select_one
61
+ # - :select_all
62
+ # - :select_value
63
+ # - :insert
64
+ # - :update
65
+ # - :delete
66
+ # - :execute
67
+ #
68
+ # There is also a special :anything symbol that will match any operation.
69
+ def have_executed(entry_point)
70
+ HaveExecuted.new(entry_point)
71
+ end
72
+
73
+ private
74
+
75
+ def self.included(other)
76
+ if nullify_contextually?(other)
77
+ contextually_nullify_database(other)
78
+ else
79
+ globally_nullify_database
80
+ end
81
+ end
82
+
83
+ def self.nullify_contextually?(other)
84
+ if defined?(RSpec)
85
+ other < RSpec::Core::ExampleGroup
86
+ else
87
+ other.is_a? Spec::ExampleGroup
88
+ end
89
+ end
90
+
91
+ def self.nullify_database(receiver)
92
+ receiver.before :all do
93
+ ActiveRecord::Base.establish_connection(:adapter => :nulldb)
94
+ end
95
+
96
+ receiver.before :each do
97
+ ActiveRecord::Base.connection.checkpoint!
98
+ end
99
+
100
+ receiver.after :all do
101
+ ActiveRecord::Base.establish_connection(:test)
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,32 @@
1
+ # Sadly, we have to monkeypatch Rake because all of the Rails database tasks are
2
+ # hardcoded for specific adapters, with no extension points (!)
3
+ Rake::TaskManager.class_eval do
4
+ def remove_task(task_name)
5
+ @tasks.delete(task_name.to_s)
6
+ end
7
+ end
8
+
9
+ def remove_task(task_name)
10
+ Rake.application.remove_task(task_name)
11
+ end
12
+
13
+ def wrap_task(task_name, &wrapper)
14
+ wrapped_task = Rake::Task[task_name]
15
+ remove_task(Rake::Task.scope_name(Rake.application.current_scope,
16
+ task_name))
17
+ task(task_name) do
18
+ wrapper.call(wrapped_task)
19
+ end
20
+ end
21
+
22
+ namespace :db do
23
+ namespace :test do
24
+ wrap_task :purge do |wrapped_task|
25
+ if ActiveRecord::Base.configurations["test"]["adapter"] == "nulldb"
26
+ # NO-OP
27
+ else
28
+ wrapped_task.invoke
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = "nulldb"
5
+ s.version = "0.3.7-alpha.1"
6
+
7
+ s.require_paths = ["lib"]
8
+ s.authors = ["Avdi Grimm", "Myron Marston"]
9
+ s.summary = "The Null Object pattern as applied to ActiveRecord database adapters"
10
+ s.description = "A database backend that translates database interactions into no-ops. Using NullDB enables you to test your model business logic - including after_save hooks - without ever touching a real database."
11
+ s.email = "myron.marston@gmail.com"
12
+ s.extra_rdoc_files = [
13
+ "LICENSE",
14
+ "README.rdoc"
15
+ ]
16
+ s.files = `git ls-files`.split($/)
17
+ s.homepage = "http://github.com/nulldb/nulldb"
18
+ s.licenses = ["MIT"]
19
+
20
+ s.add_runtime_dependency 'activerecord', '>= 2.0.0'
21
+ s.add_development_dependency 'spec'
22
+ s.add_development_dependency 'rspec'
23
+ s.add_development_dependency 'rake'
24
+ s.add_development_dependency 'appraisal'
25
+ s.add_development_dependency 'simplecov'
26
+ end
27
+
@@ -0,0 +1,345 @@
1
+ require 'rubygems'
2
+
3
+ # Optional simplecov loading
4
+ begin
5
+ require 'simplecov'
6
+ SimpleCov.start
7
+ rescue LoadError
8
+ end
9
+
10
+ require 'active_record'
11
+ require 'active_record/version'
12
+ $: << File.join(File.dirname(__FILE__), "..", "lib")
13
+
14
+ if ActiveRecord::VERSION::MAJOR > 2
15
+ require 'rspec' # rspec 2
16
+ else
17
+ require 'spec' # rspec 1
18
+ end
19
+
20
+ require 'nulldb_rspec'
21
+
22
+ class Employee < ActiveRecord::Base
23
+ after_save :on_save_finished
24
+
25
+ def on_save_finished
26
+ end
27
+ end
28
+
29
+ class TablelessModel < ActiveRecord::Base
30
+ end
31
+
32
+ NullDB.configure {|ndb| ndb.project_root = 'Rails.root'}
33
+
34
+ describe "NullDB with no schema pre-loaded" do
35
+ before :each do
36
+ allow( Kernel ).to receive :load
37
+ allow( ActiveRecord::Migration ).to receive :verbose=
38
+ end
39
+
40
+ it "should load Rails.root/db/schema.rb if no alternate is specified" do
41
+ ActiveRecord::Base.establish_connection :adapter => :nulldb
42
+ expect( Kernel ).to receive(:load).with("Rails.root/db/schema.rb")
43
+ ActiveRecord::Base.connection.columns('schema_info')
44
+ end
45
+
46
+ it "should load the specified schema relative to Rails.root" do
47
+ expect( Kernel ).to receive(:load).with("Rails.root/foo/myschema.rb")
48
+ ActiveRecord::Base.establish_connection :adapter => :nulldb,
49
+ :schema => "foo/myschema.rb"
50
+ ActiveRecord::Base.connection.columns('schema_info')
51
+ end
52
+
53
+ it "should suppress migration output" do
54
+ expect( ActiveRecord::Migration).to receive(:verbose=).with(false)
55
+ ActiveRecord::Base.establish_connection :adapter => :nulldb,
56
+ :schema => "foo/myschema.rb"
57
+ ActiveRecord::Base.connection.columns('schema_info')
58
+ end
59
+
60
+ it "should allow creating a table without passing a block" do
61
+ ActiveRecord::Base.establish_connection :adapter => :nulldb
62
+ ActiveRecord::Schema.define do
63
+ create_table(:employees)
64
+ end
65
+ end
66
+ end
67
+
68
+ describe "NullDB" do
69
+ before :all do
70
+ ActiveRecord::Base.establish_connection :adapter => :nulldb
71
+ ActiveRecord::Migration.verbose = false
72
+ ActiveRecord::Schema.define do
73
+ create_table(:employees) do |t|
74
+ t.string :name, null: false, limit: 50
75
+ t.date :hire_date
76
+ t.integer :employee_number
77
+ t.decimal :salary
78
+ end
79
+
80
+ create_table(:employees_widgets, :id => false, :force => true) do |t|
81
+ t.integer :employee_id
82
+ t.integer :widget_id
83
+ end
84
+
85
+ add_index "employees", :name, :name => "index_employees_on_name"
86
+ add_index "employees", ["employee_number"], :name => "index_employees_on_employee_number", :unique => true
87
+ add_index "employees_widgets", ["employee_id", "widget_id"], :name => "my_index"
88
+
89
+ add_fk_constraint "foo", "bar", "baz", "buz", "bungle"
90
+ add_pk_constraint "foo", "bar", {}, "baz", "buz"
91
+ end
92
+ end
93
+
94
+ before :each do
95
+ @employee = Employee.new(:name => "John Smith",
96
+ :hire_date => Date.civil(2000, 1, 1),
97
+ :employee_number => 42,
98
+ :salary => 56000.00)
99
+ end
100
+
101
+ it "should set the @config instance variable so plugins that assume its there can use it" do
102
+ expect( Employee.connection.instance_variable_get(:@config)[:adapter]).to eq :nulldb
103
+ end
104
+
105
+ it "should enable instantiation of AR objects without a database" do
106
+ expect( @employee ).to be_a_kind_of(ActiveRecord::Base)
107
+ end
108
+
109
+ it "should remember columns defined in migrations" do
110
+ should_have_column(Employee, :name, :string)
111
+ should_have_column(Employee, :hire_date, :date)
112
+ should_have_column(Employee, :employee_number, :integer)
113
+ should_have_column(Employee, :salary, :decimal)
114
+ end
115
+
116
+ it 'should have limit on name' do
117
+ expect(Employee.columns_hash['name'].limit).to eq 50
118
+ end
119
+
120
+ it "should return true on nullable field" do
121
+ expect(Employee.columns_hash['salary'].null).to be true
122
+ end
123
+
124
+ it "should return false on non-nullable field" do
125
+ expect(Employee.columns_hash['name'].null).to be false
126
+ end
127
+
128
+ it "should return the appropriate primary key" do
129
+ expect( ActiveRecord::Base.connection.primary_key('employees') ).to eq 'id'
130
+ end
131
+
132
+ it "should return a nil primary key on habtm" do
133
+ expect( ActiveRecord::Base.connection.primary_key('employees_widgets') ).to eq nil
134
+ end
135
+
136
+ it "should return an empty array of columns for a table-less model" do
137
+ expect( TablelessModel.columns).to eq []
138
+ end
139
+
140
+ it "should enable simulated saving of AR objects" do
141
+ expect{ @employee.save! }.to_not raise_error
142
+ end
143
+
144
+ it "should enable AR callbacks during simulated save" do
145
+ expect( @employee ).to receive :on_save_finished
146
+ @employee.save
147
+ end
148
+
149
+ it "should enable simulated deletes of AR objects" do
150
+ expect{ @employee.destroy }.to_not raise_error
151
+ end
152
+
153
+ it "should enable simulated creates of AR objects" do
154
+ emp = Employee.create(:name => "Bob Jones")
155
+ expect( emp.name ).to eq "Bob Jones"
156
+ end
157
+
158
+ it "should generate new IDs when inserting unsaved objects" do
159
+ cxn = Employee.connection
160
+ id1 = cxn.insert("some sql", "SomeClass Create", "id", nil, nil)
161
+ id2 = cxn.insert("some sql", "SomeClass Create", "id", nil, nil)
162
+ expect( id2 ).to eq (id1 + 1)
163
+ end
164
+
165
+ it "should re-use object ID when inserting saved objects" do
166
+ cxn = Employee.connection
167
+ id1 = cxn.insert("some sql", "SomeClass Create", "id", 23, nil)
168
+ expect( id1 ).to eq 23
169
+ end
170
+
171
+ it "should log executed SQL statements" do
172
+ cxn = Employee.connection
173
+ exec_count = cxn.execution_log.size
174
+ @employee.save!
175
+ expect( cxn.execution_log.size ).to eq (exec_count + 1)
176
+ end
177
+
178
+ it "should have the adapter name 'NullDB'" do
179
+ expect( Employee.connection.adapter_name ).to eq "NullDB"
180
+ end
181
+
182
+ it "should support migrations" do
183
+ expect( Employee.connection.supports_migrations? ).to eq true
184
+ end
185
+
186
+ it "should always have a schema_info table definition" do
187
+ expect( Employee.connection.tables ).to include "schema_info"
188
+ end
189
+
190
+ it "should return an empty array from #select" do
191
+ result = Employee.connection.select_all("who cares", "blah")
192
+ expect( result ).to eq []
193
+ end
194
+
195
+ it "should provide a way to set log checkpoints" do
196
+ cxn = Employee.connection
197
+ @employee.save!
198
+ expect( cxn.execution_log_since_checkpoint.size ).to be > 0
199
+
200
+ cxn.checkpoint!
201
+ expect( cxn.execution_log_since_checkpoint.size ).to eq 0
202
+
203
+ @employee.salary = @employee.salary + 1
204
+ @employee.save!
205
+ expect( cxn.execution_log_since_checkpoint.size ).to eq 1
206
+ end
207
+
208
+ def should_contain_statement(cxn, entry_point)
209
+ expect( cxn.execution_log_since_checkpoint).to \
210
+ include(ActiveRecord::ConnectionAdapters::NullDBAdapter::Statement.new(entry_point))
211
+ end
212
+
213
+ def should_not_contain_statement(cxn, entry_point)
214
+ expect( cxn.execution_log_since_checkpoint ).to_not \
215
+ include(ActiveRecord::ConnectionAdapters::NullDBAdapter::Statement.new(entry_point))
216
+ end
217
+
218
+ it "should tag logged statements with their entry point" do
219
+ cxn = Employee.connection
220
+
221
+ should_not_contain_statement(cxn, :insert)
222
+ @employee.save
223
+ should_contain_statement(cxn, :insert)
224
+
225
+ cxn.checkpoint!
226
+ should_not_contain_statement(cxn, :update)
227
+ @employee.salary = @employee.salary + 1
228
+ @employee.save
229
+ should_contain_statement(cxn, :update)
230
+
231
+ cxn.checkpoint!
232
+ should_not_contain_statement(cxn, :delete)
233
+ @employee.destroy
234
+ should_contain_statement(cxn, :delete)
235
+
236
+ cxn.checkpoint!
237
+ should_not_contain_statement(cxn, :select_all)
238
+ Employee.all.each do |emp|; end
239
+ should_contain_statement(cxn, :select_all)
240
+
241
+ cxn.checkpoint!
242
+ should_not_contain_statement(cxn, :select_value)
243
+ Employee.count_by_sql("frobozz")
244
+ should_contain_statement(cxn, :select_value)
245
+
246
+ cxn.checkpoint!
247
+ should_not_contain_statement(cxn, :select_values)
248
+ cxn.select_values("")
249
+ should_contain_statement(cxn, :select_values)
250
+ end
251
+
252
+ it "should allow #finish to be called on the result of #execute" do
253
+ Employee.connection.execute("blah").finish
254
+ end
255
+
256
+ it "should #to_a return empty array on the result of #execute" do
257
+ result = Employee.connection.execute("blah")
258
+ expect( result.to_a ).to be_a Array
259
+ expect( result.to_a ).to be_empty
260
+ end
261
+
262
+ def should_have_column(klass, col_name, col_type)
263
+ col = klass.columns_hash[col_name.to_s]
264
+ expect(col.sql_type.to_s.gsub(/\([0-9]+\)/, "").to_sym).to eq col_type
265
+ end
266
+
267
+
268
+ it "should support adding indexes" do
269
+ expect( Employee.connection.indexes('employees').size ).to eq 2
270
+ expect( Employee.connection.indexes('employees_widgets').size ).to eq 1
271
+ end
272
+
273
+ it "should support unique indexes" do
274
+ expect( Employee.connection.indexes('employees').detect{|idx| idx.columns == ["name"]}.unique ).to eq false
275
+ expect( Employee.connection.indexes('employees').detect{|idx| idx.columns == ["employee_number"]}.unique ).to eq true
276
+ end
277
+
278
+ it "should support multi-column indexes" do
279
+ expect( Employee.connection.indexes('employees_widgets').first.columns).to eq ["employee_id", "widget_id"]
280
+ end
281
+
282
+ it "should support custom index names" do
283
+ expect( Employee.connection.indexes('employees_widgets').first.name ).to eq 'my_index'
284
+ end
285
+
286
+ it 'should handle ActiveRecord::ConnectionNotEstablished' do
287
+ expect( ActiveRecord::Base ).to receive(:connection_pool).and_raise(ActiveRecord::ConnectionNotEstablished)
288
+ expect { NullDB.nullify }.to_not raise_error
289
+ end
290
+ end
291
+
292
+ # need a fallback db for contextual nullification
293
+ ActiveRecord::Base.configurations['test'] = {'adapter' => 'nulldb'}
294
+
295
+ describe NullDB::RSpec::NullifiedDatabase do
296
+ describe 'have_executed rspec matcher' do
297
+ before(:all) do
298
+ ActiveRecord::Schema.define do
299
+ create_table(:employees)
300
+ end
301
+ end
302
+
303
+ include NullDB::RSpec::NullifiedDatabase
304
+
305
+ before { NullDB.checkpoint }
306
+
307
+ it 'passes if an execution was made' do
308
+ expect( Employee.connection ).to receive(:insert)
309
+ allow( Kernel ).to receive :load
310
+ Employee.create
311
+ end
312
+ end
313
+
314
+ describe '.globally_nullify_database' do
315
+ it 'nullifies the database' do
316
+ expect( NullDB::RSpec::NullifiedDatabase ).to respond_to(:nullify_database)
317
+ expect( NullDB::RSpec::NullifiedDatabase ).to receive(:nullify_database)
318
+ NullDB::RSpec::NullifiedDatabase.globally_nullify_database
319
+ end
320
+ end
321
+ end
322
+
323
+
324
+ describe 'adapter-specific extensions' do
325
+ before(:all) do
326
+ ActiveRecord::Base.establish_connection :adapter => :nulldb
327
+ ActiveRecord::Migration.verbose = false
328
+ end
329
+
330
+ it "supports 'enable_extension' in the schema definition" do
331
+ expect{
332
+ ActiveRecord::Schema.define do
333
+ enable_extension "plpgsql"
334
+ end
335
+ }.to_not raise_error
336
+ end
337
+ end
338
+
339
+ describe ActiveRecord::ConnectionAdapters::NullDBAdapter::EmptyResult do
340
+ it "should return an empty array from #cast_values" do
341
+ result = described_class.new
342
+ expect( result.cast_values ).to be_a Array
343
+ expect( result.cast_values ).to be_empty
344
+ end
345
+ end