sequel 0.1.7 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,270 @@
1
+ require File.join(File.dirname(__FILE__), '../lib/sequel')
2
+
3
+ context "An empty ConnectionPool" do
4
+ setup do
5
+ @cpool = Sequel::ConnectionPool.new
6
+ end
7
+
8
+ specify "should have no available connections" do
9
+ @cpool.available_connections.should == []
10
+ end
11
+
12
+ specify "should have no allocated connections" do
13
+ @cpool.allocated.should == {}
14
+ end
15
+
16
+ specify "should have a created_count of zero" do
17
+ @cpool.created_count.should == 0
18
+ end
19
+ end
20
+
21
+ context "A connection pool handling connections" do
22
+ setup do
23
+ @max_size = 2
24
+ @cpool = Sequel::ConnectionPool.new(@max_size) {:got_connection}
25
+ end
26
+
27
+ specify "#hold should increment #created_count" do
28
+ @cpool.hold do
29
+ @cpool.created_count.should == 1
30
+ @cpool.hold {@cpool.created_count.should == 1}
31
+ end
32
+ end
33
+
34
+ specify "#hold should add the connection to the #allocated hash" do
35
+ @cpool.hold do
36
+ @cpool.allocated.size.should == 1
37
+
38
+ @cpool.allocated.values.should == [:got_connection]
39
+ end
40
+ end
41
+
42
+ specify "#hold should yield a new connection" do
43
+ @cpool.hold {|conn| conn.should == :got_connection}
44
+ end
45
+
46
+ specify "a connection should be de-allocated after it has been used in #hold" do
47
+ @cpool.hold {}
48
+ @cpool.allocated.size.should == 0
49
+ end
50
+
51
+ specify "#hold should return the value of its block" do
52
+ @cpool.hold {:block_return}.should == :block_return
53
+ end
54
+
55
+ specify "#make_new should not make more than max_size connections" do
56
+ @cpool.send(:make_new).should == :got_connection
57
+ @cpool.send(:make_new).should == :got_connection
58
+ @cpool.send(:make_new).should == nil
59
+ @cpool.created_count.should == 2
60
+ end
61
+ end
62
+
63
+ class DummyConnection
64
+ @@value = 0
65
+ def initialize
66
+ @@value += 1
67
+ end
68
+
69
+ def value
70
+ @@value
71
+ end
72
+ end
73
+
74
+ context "ConnectionPool#hold" do
75
+ setup do
76
+ @pool = Sequel::ConnectionPool.new {DummyConnection.new}
77
+ end
78
+
79
+ specify "should pass the result of the connection maker proc to the supplied block" do
80
+ res = nil
81
+ @pool.hold {|c| res = c}
82
+ res.should be_a_kind_of(DummyConnection)
83
+ res.value.should == 1
84
+ @pool.hold {|c| res = c}
85
+ res.should be_a_kind_of(DummyConnection)
86
+ res.value.should == 1 # the connection maker is invoked only once
87
+ end
88
+
89
+ specify "should be re-entrant by the same thread" do
90
+ cc = nil
91
+ @pool.hold {|c| @pool.hold {|c| @pool.hold {|c| cc = c}}}
92
+ cc.should be_a_kind_of(DummyConnection)
93
+ end
94
+
95
+ specify "should catch exceptions and reraise them" do
96
+ proc {@pool.hold {|c| c.foobar}}.should raise_error(NoMethodError)
97
+ end
98
+
99
+ specify "should handle Exception errors (normally not caught be rescue)" do
100
+ begin
101
+ @pool.hold {raise Exception}
102
+ rescue => e
103
+ e.should be_a_kind_of(RuntimeError)
104
+ end
105
+ end
106
+ end
107
+
108
+ context "ConnectionPool#connection_proc" do
109
+ setup do
110
+ @pool = Sequel::ConnectionPool.new
111
+ end
112
+
113
+ specify "should be nil if no block is supplied to the pool" do
114
+ @pool.connection_proc.should be_nil
115
+ proc {@pool.hold {}}.should raise_error
116
+ end
117
+
118
+ specify "should be mutable" do
119
+ @pool.connection_proc = proc {'herro'}
120
+ res = nil
121
+ proc {@pool.hold {|c| res = c}}.should_not raise_error
122
+ res.should == 'herro'
123
+ end
124
+ end
125
+
126
+ context "A connection pool with a max size of 1" do
127
+ setup do
128
+ @invoked_count = 0
129
+ @pool = Sequel::ConnectionPool.new(1) {@invoked_count += 1;'herro'}
130
+ end
131
+
132
+ specify "should let only one thread access the connection at any time" do
133
+ cc,c1, c2 = nil
134
+
135
+ t1 = Thread.new {@pool.hold {|c| cc = c; c1 = c.dup; while c == 'herro';sleep 0.1;end}}
136
+ sleep 0.2
137
+ cc.should == 'herro'
138
+ c1.should == 'herro'
139
+
140
+ t2 = Thread.new {@pool.hold {|c| c2 = c.dup; while c == 'hello';sleep 0.1;end}}
141
+ sleep 0.2
142
+
143
+ # connection held by t1
144
+ t1.should be_alive
145
+ t2.should be_alive
146
+
147
+ cc.should == 'herro'
148
+ c1.should == 'herro'
149
+ c2.should be_nil
150
+
151
+ @pool.available_connections.should be_empty
152
+ @pool.allocated.should == {t1 => cc}
153
+
154
+ cc.gsub!('rr', 'll')
155
+ sleep 0.2
156
+
157
+ # connection held by t2
158
+ t1.should_not be_alive
159
+ t2.should be_alive
160
+
161
+ c2.should == 'hello'
162
+
163
+ @pool.available_connections.should be_empty
164
+ @pool.allocated.should == {t2 => cc}
165
+
166
+ cc.gsub!('ll', 'rr')
167
+ sleep 0.2
168
+
169
+ #connection released
170
+ t2.should_not be_alive
171
+
172
+ cc.should == 'herro'
173
+
174
+ @invoked_count.should == 1
175
+ @pool.size.should == 1
176
+ @pool.available_connections.should == [cc]
177
+ @pool.allocated.should be_empty
178
+ end
179
+
180
+ specify "should let the same thread reenter #hold" do
181
+ c1, c2, c3 = nil
182
+ @pool.hold do |c|
183
+ c1 = c
184
+ @pool.hold do |c|
185
+ c2 = c
186
+ @pool.hold do |c|
187
+ c3 = c
188
+ end
189
+ end
190
+ end
191
+ c1.should == 'herro'
192
+ c2.should == 'herro'
193
+ c3.should == 'herro'
194
+
195
+ @invoked_count.should == 1
196
+ @pool.size.should == 1
197
+ @pool.available_connections.size.should == 1
198
+ @pool.allocated.should be_empty
199
+ end
200
+ end
201
+
202
+ context "A connection pool with a max size of 5" do
203
+ setup do
204
+ @invoked_count = 0
205
+ @pool = Sequel::ConnectionPool.new(5) {@invoked_count += 1}
206
+ end
207
+
208
+ specify "should let five threads simulatneously access separate connections" do
209
+ cc = {}
210
+ threads = []
211
+ stop = nil
212
+
213
+ 5.times {|i| threads << Thread.new {@pool.hold {|c| cc[i] = c; while !stop;sleep 0.1;end}}; sleep 0.1}
214
+ sleep 0.2
215
+ threads.each {|t| t.should be_alive}
216
+ cc.size.should == 5
217
+ @invoked_count.should == 5
218
+ @pool.size.should == 5
219
+ @pool.available_connections.should be_empty
220
+ @pool.allocated.should == {threads[0] => 1, threads[1] => 2, threads[2] => 3,
221
+ threads[3] => 4, threads[4] => 5}
222
+
223
+ threads[0].raise "your'e dead"
224
+ sleep 0.1
225
+ threads[3].raise "your'e dead too"
226
+
227
+ sleep 0.1
228
+
229
+ @pool.available_connections.should == [1, 4]
230
+ @pool.allocated.should == {threads[1] => 2, threads[2] => 3, threads[4] => 5}
231
+
232
+ stop = true
233
+ sleep 0.2
234
+
235
+ @pool.available_connections.size.should == 5
236
+ @pool.allocated.should be_empty
237
+ end
238
+
239
+ specify "should block threads until a connection becomes available" do
240
+ cc = {}
241
+ threads = []
242
+ stop = nil
243
+
244
+ 5.times {|i| threads << Thread.new {@pool.hold {|c| cc[i] = c; while !stop;sleep 0.1;end}}; sleep 0.1}
245
+ sleep 0.2
246
+ threads.each {|t| t.should be_alive}
247
+ @pool.available_connections.should be_empty
248
+
249
+ 3.times {|i| threads << Thread.new {@pool.hold {|c| cc[i + 5] = c}}}
250
+
251
+ sleep 0.2
252
+ threads[5].should be_alive
253
+ threads[6].should be_alive
254
+ threads[7].should be_alive
255
+ cc.size.should == 5
256
+ cc[5].should be_nil
257
+ cc[6].should be_nil
258
+ cc[7].should be_nil
259
+
260
+ stop = true
261
+ sleep 0.3
262
+
263
+ threads.each {|t| t.should_not be_alive}
264
+
265
+ @pool.size.should == 5
266
+ @invoked_count.should == 5
267
+ @pool.available_connections.size.should == 5
268
+ @pool.allocated.should be_empty
269
+ end
270
+ end
@@ -0,0 +1,127 @@
1
+ require File.join(File.dirname(__FILE__), '../lib/sequel')
2
+
3
+ context "Enumerable#send_each" do
4
+ specify "should send the supplied method to each item" do
5
+ a = ['abbc', 'bbccdd', 'hebtre']
6
+ a.send_each(:gsub!, 'b', '_')
7
+ a.should == ['a__c', '__ccdd', 'he_tre']
8
+ end
9
+ end
10
+
11
+ context "Array#to_sql" do
12
+ specify "should concatenate multiple lines into a single string" do
13
+ "SELECT * \r\nFROM items\r\n WHERE a = 1".split.to_sql. \
14
+ should == 'SELECT * FROM items WHERE a = 1'
15
+ end
16
+
17
+ specify "should remove superfluous white space and line breaks" do
18
+ "\tSELECT * \n FROM items ".split.to_sql. \
19
+ should == 'SELECT * FROM items'
20
+ end
21
+
22
+ specify "should remove ANSI SQL comments" do
23
+ "SELECT * --comment\r\n FROM items\r\n --comment".split.to_sql. \
24
+ should == 'SELECT * FROM items'
25
+ end
26
+
27
+ specify "should remove C-style comments" do
28
+ "SELECT * \r\n /* comment comment\r\n comment\r\n FROM items */\r\n FROM items\r\n--comment".split.to_sql. \
29
+ should == 'SELECT * FROM items'
30
+ end
31
+ end
32
+
33
+ context "String#to_sql" do
34
+ specify "should concatenate multiple lines into a single string" do
35
+ "SELECT * \r\nFROM items\r\nWHERE a = 1".to_sql. \
36
+ should == 'SELECT * FROM items WHERE a = 1'
37
+ end
38
+
39
+ specify "should remove superfluous white space and line breaks" do
40
+ "\tSELECT * \r\n FROM items ".to_sql. \
41
+ should == 'SELECT * FROM items'
42
+ end
43
+
44
+ specify "should remove ANSI SQL comments" do
45
+ "SELECT * --comment \r\n FROM items\r\n --comment".to_sql. \
46
+ should == 'SELECT * FROM items'
47
+ end
48
+
49
+ specify "should remove C-style comments" do
50
+ "SELECT * \r\n/* comment comment\r\ncomment\r\nFROM items */\r\nFROM items\r\n--comment".to_sql. \
51
+ should == 'SELECT * FROM items'
52
+ end
53
+ end
54
+
55
+ context "String#expr" do
56
+ specify "should return an ExpressionString object" do
57
+ 'xyz'.expr.should be_a_kind_of(Sequel::ExpressionString)
58
+ 'xyz'.expr.to_s.should == 'xyz'
59
+ end
60
+ end
61
+
62
+ context "String#split_sql" do
63
+ specify "should split a string containing multiple statements" do
64
+ "DROP TABLE a; DROP TABLE c".split_sql.should == \
65
+ ['DROP TABLE a', 'DROP TABLE c']
66
+ end
67
+
68
+ specify "should remove comments from the string" do
69
+ "DROP TABLE a;/* DROP TABLE b; DROP TABLE c;*/DROP TABLE d".split_sql.should == \
70
+ ['DROP TABLE a', 'DROP TABLE d']
71
+ end
72
+ end
73
+
74
+ context "Symbol#DESC" do
75
+ specify "should append the symbol with DESC" do
76
+ :hey.DESC.should == 'hey DESC'
77
+ end
78
+
79
+ specify "should support qualified symbol notation" do
80
+ :abc__def.DESC.should == 'abc.def DESC'
81
+ end
82
+ end
83
+
84
+ context "Symbol#AS" do
85
+ specify "should append an AS clause" do
86
+ :hey.AS(:ho).should == 'hey AS ho'
87
+ end
88
+
89
+ specify "should support qualified symbol notation" do
90
+ :abc__def.AS(:x).should == 'abc.def AS x'
91
+ end
92
+ end
93
+
94
+ context "Symbol#ALL" do
95
+ specify "should format a qualified wildcard" do
96
+ :xyz.ALL.should == 'xyz.*'
97
+ end
98
+ end
99
+
100
+ context "Symbol#to_field_name" do
101
+ specify "should convert qualified symbol notation into dot notation" do
102
+ :abc__def.to_field_name.should == 'abc.def'
103
+ end
104
+
105
+ specify "should convert AS symbol notation into SQL AS notation" do
106
+ :xyz___x.to_field_name.should == 'xyz AS x'
107
+ :abc__def___x.to_field_name.should == 'abc.def AS x'
108
+ end
109
+ end
110
+
111
+ context "Symbol" do
112
+ specify "should support MIN for specifying min function" do
113
+ :abc__def.MIN.should == 'min(abc.def)'
114
+ end
115
+
116
+ specify "should support MAX for specifying max function" do
117
+ :abc__def.MAX.should == 'max(abc.def)'
118
+ end
119
+
120
+ specify "should support SUM for specifying sum function" do
121
+ :abc__def.SUM.should == 'sum(abc.def)'
122
+ end
123
+
124
+ specify "should support AVG for specifying avg function" do
125
+ :abc__def.AVG.should == 'avg(abc.def)'
126
+ end
127
+ end
@@ -0,0 +1,366 @@
1
+ require File.join(File.dirname(__FILE__), '../lib/sequel')
2
+
3
+ context "A new Database" do
4
+ setup do
5
+ @db = Sequel::Database.new(1 => 2, :logger => 3)
6
+ end
7
+
8
+ specify "should receive options" do
9
+ @db.opts.should == {1 => 2, :logger => 3}
10
+ end
11
+
12
+ specify "should set the logger from opts[:logger]" do
13
+ @db.logger.should == 3
14
+ end
15
+
16
+ specify "should create a connection pool" do
17
+ @db.pool.should be_a_kind_of(Sequel::ConnectionPool)
18
+ @db.pool.max_size.should == 4
19
+
20
+ Sequel::Database.new(:max_connections => 10).pool.max_size.should == 10
21
+ end
22
+
23
+ specify "should pass the supplied block to the connection pool" do
24
+ cc = nil
25
+ d = Sequel::Database.new {1234}
26
+ d.synchronize {|c| cc = c}
27
+ cc.should == 1234
28
+ end
29
+ end
30
+
31
+ context "Database#connect" do
32
+ specify "should raise NotImplementedError" do
33
+ proc {Sequel::Database.new.connect}.should raise_error(NotImplementedError)
34
+ end
35
+ end
36
+
37
+ context "Database#uri" do
38
+ setup do
39
+ @c = Class.new(Sequel::Database) do
40
+ set_adapter_scheme :mau
41
+ end
42
+
43
+ @db = Sequel('mau://user:pass@localhost:9876/maumau')
44
+ end
45
+
46
+ specify "should return the connection URI for the database" do
47
+ @db.uri.should == 'mau://user:pass@localhost:9876/maumau'
48
+ end
49
+ end
50
+
51
+ context "Database.adapter_scheme" do
52
+ specify "should return the database schema" do
53
+ Sequel::Database.adapter_scheme.should be_nil
54
+
55
+ @c = Class.new(Sequel::Database) do
56
+ set_adapter_scheme :mau
57
+ end
58
+
59
+ @c.adapter_scheme.should == :mau
60
+ end
61
+ end
62
+
63
+ context "Database#dataset" do
64
+ setup do
65
+ @db = Sequel::Database.new
66
+ @ds = @db.dataset
67
+ end
68
+
69
+ specify "should provide a blank dataset through #dataset" do
70
+ @ds.should be_a_kind_of(Sequel::Dataset)
71
+ @ds.opts.should == {}
72
+ @ds.db.should be(@db)
73
+ end
74
+
75
+ specify "should provide a #from dataset" do
76
+ d = @db.from(:mau)
77
+ d.should be_a_kind_of(Sequel::Dataset)
78
+ d.sql.should == 'SELECT * FROM mau'
79
+
80
+ e = @db[:miu]
81
+ e.should be_a_kind_of(Sequel::Dataset)
82
+ e.sql.should == 'SELECT * FROM miu'
83
+ end
84
+
85
+ specify "should provide a #select dataset" do
86
+ d = @db.select(:a, :b, :c).from(:mau)
87
+ d.should be_a_kind_of(Sequel::Dataset)
88
+ d.sql.should == 'SELECT a, b, c FROM mau'
89
+ end
90
+ end
91
+
92
+ context "Database#execute" do
93
+ specify "should raise NotImplementedError" do
94
+ proc {Sequel::Database.new.execute('blah blah')}.should raise_error(NotImplementedError)
95
+ proc {Sequel::Database.new << 'blah blah'}.should raise_error(NotImplementedError)
96
+ end
97
+ end
98
+
99
+ context "Database#<<" do
100
+ setup do
101
+ @c = Class.new(Sequel::Database) do
102
+ define_method(:execute) {|sql| sql}
103
+ end
104
+ @db = @c.new({})
105
+ end
106
+
107
+ specify "should pass the supplied sql to #execute" do
108
+ (@db << "DELETE FROM items").should == "DELETE FROM items"
109
+ end
110
+
111
+ specify "should accept an array and convert it to SQL" do
112
+ a = %[
113
+ --
114
+ CREATE TABLE items (a integer, /*b integer*/
115
+ b text, c integer);
116
+ DROP TABLE old_items;
117
+ ].split($/)
118
+ (@db << a).should ==
119
+ "CREATE TABLE items (a integer, b text, c integer); DROP TABLE old_items;"
120
+ end
121
+
122
+ specify "should remove comments and whitespace from strings as well" do
123
+ s = %[
124
+ --
125
+ CREATE TABLE items (a integer, /*b integer*/
126
+ b text, c integer); \r\n
127
+ DROP TABLE old_items;
128
+ ]
129
+ (@db << s).should ==
130
+ "CREATE TABLE items (a integer, b text, c integer); DROP TABLE old_items;"
131
+ end
132
+ end
133
+
134
+ context "Database#synchronize" do
135
+ setup do
136
+ @db = Sequel::Database.new(:max_connections => 1)
137
+ @db.pool.connection_proc = proc {12345}
138
+ end
139
+
140
+ specify "should wrap the supplied block in pool.hold" do
141
+ stop = false
142
+ c1, c2 = nil
143
+ t1 = Thread.new {@db.synchronize {|c| c1 = c; while !stop;sleep 0.1;end}}
144
+ while !c1;end
145
+ c1.should == 12345
146
+ t2 = Thread.new {@db.synchronize {|c| c2 = c}}
147
+ sleep 0.2
148
+ @db.pool.available_connections.should be_empty
149
+ c2.should be_nil
150
+ stop = true
151
+ t1.join
152
+ sleep 0.1
153
+ c2.should == 12345
154
+ t2.join
155
+ end
156
+ end
157
+
158
+ context "Database#test_connection" do
159
+ setup do
160
+ @db = Sequel::Database.new
161
+ @test = nil
162
+ @db.pool.connection_proc = proc {@test = rand(100)}
163
+ end
164
+
165
+ specify "should call pool#hold" do
166
+ @db.test_connection
167
+ @test.should_not be_nil
168
+ end
169
+
170
+ specify "should return true if successful" do
171
+ @db.test_connection.should be_true
172
+ end
173
+ end
174
+
175
+ class DummyDataset < Sequel::Dataset
176
+ def first
177
+ raise if @opts[:from] == [:a]
178
+ true
179
+ end
180
+ end
181
+
182
+ class DummyDatabase < Sequel::Database
183
+ attr_reader :sql
184
+ def execute(sql); @sql = sql; end
185
+
186
+ def dataset
187
+ DummyDataset.new(self)
188
+ end
189
+ end
190
+
191
+ context "Database#create_table" do
192
+ setup do
193
+ @db = DummyDatabase.new
194
+ end
195
+
196
+ specify "should construct proper SQL" do
197
+ @db.create_table :test do
198
+ primary_key :id, :integer, :null => false
199
+ column :name, :text
200
+ index :name, :unique => true
201
+ end
202
+ @db.sql.should ==
203
+ 'CREATE TABLE test (id integer NOT NULL PRIMARY KEY, name text);CREATE UNIQUE INDEX test_name_index ON test (name);'
204
+ end
205
+ end
206
+
207
+ class Dummy2Database < Sequel::Database
208
+ attr_reader :sql
209
+ def execute(sql); @sql = sql; end
210
+ def transaction; yield; end
211
+ end
212
+
213
+ context "Database#drop_table" do
214
+ setup do
215
+ @db = Dummy2Database.new
216
+ end
217
+
218
+ specify "should construct proper SQL" do
219
+ @db.drop_table :test
220
+ @db.sql.should ==
221
+ 'DROP TABLE test CASCADE;'
222
+ end
223
+
224
+ specify "should accept multiple table names" do
225
+ @db.drop_table :a, :bb, :ccc
226
+ @db.sql.should ==
227
+ 'DROP TABLE a CASCADE;DROP TABLE bb CASCADE;DROP TABLE ccc CASCADE;'
228
+ end
229
+ end
230
+
231
+ context "Database#table_exists?" do
232
+ setup do
233
+ @db = DummyDatabase.new
234
+ @db.stub!(:tables).and_return([:a, :b])
235
+ @db2 = DummyDatabase.new
236
+ Sequel::Dataset.stub!(:first).and_return(nil)
237
+ end
238
+
239
+ specify "should use Database#tables if available" do
240
+ @db.table_exists?(:a).should be_true
241
+ @db.table_exists?(:b).should be_true
242
+ @db.table_exists?(:c).should be_false
243
+ end
244
+
245
+ specify "should otherise try to select the first record from the table's dataset" do
246
+ @db2.table_exists?(:a).should be_false
247
+ @db2.table_exists?(:b).should be_true
248
+ end
249
+ end
250
+
251
+
252
+ class Dummy3Database < Sequel::Database
253
+ attr_reader :sql, :transactions
254
+ def execute(sql); @sql ||= []; @sql << sql; end
255
+
256
+ class DummyConnection
257
+ def initialize(db); @db = db; end
258
+ def execute(sql); @db.execute(sql); end
259
+ end
260
+ end
261
+
262
+ context "Database#transaction" do
263
+ setup do
264
+ @db = Dummy3Database.new
265
+ @db.pool.connection_proc = proc {Dummy3Database::DummyConnection.new(@db)}
266
+ end
267
+
268
+ specify "should wrap the supplied block with BEGIN + COMMIT statements" do
269
+ @db.transaction {@db.execute 'DROP TABLE test;'}
270
+ @db.sql.should == ['BEGIN', 'DROP TABLE test;', 'COMMIT']
271
+ end
272
+
273
+ specify "should issue ROLLBACK if an exception is raised, and re-raise" do
274
+ @db.transaction {@db.execute 'DROP TABLE test;'; raise RuntimeError} rescue nil
275
+ @db.sql.should == ['BEGIN', 'DROP TABLE test;', 'ROLLBACK']
276
+
277
+ proc {@db.transaction {raise RuntimeError}}.should raise_error(RuntimeError)
278
+ end
279
+
280
+ specify "should be re-entrant" do
281
+ stop = false
282
+ cc = nil
283
+ t = Thread.new do
284
+ @db.transaction {@db.transaction {@db.transaction {|c|
285
+ cc = c
286
+ while !stop; sleep 0.1; end
287
+ }}}
288
+ end
289
+ while cc.nil?; sleep 0.1; end
290
+ cc.should be_a_kind_of(Dummy3Database::DummyConnection)
291
+ @db.transactions.should == [t]
292
+ stop = true
293
+ t.join
294
+ @db.transactions.should be_empty
295
+ end
296
+ end
297
+
298
+ class Sequel::Database
299
+ def self.get_adapters; @@adapters; end
300
+ end
301
+
302
+ context "A Database adapter with a scheme" do
303
+ setup do
304
+ class CCC < Sequel::Database
305
+ set_adapter_scheme :ccc
306
+ end
307
+ end
308
+
309
+ specify "should be registered in adapters" do
310
+ Sequel::Database.get_adapters[:ccc].should == CCC
311
+ end
312
+
313
+ specify "should be instantiated when its scheme is specified" do
314
+ c = Sequel::Database.connect('ccc://localhost/db')
315
+ c.should be_a_kind_of(CCC)
316
+ c.opts[:host].should == 'localhost'
317
+ c.opts[:database].should == 'db'
318
+ end
319
+
320
+ specify "should be accessible through Sequel.connect" do
321
+ c = Sequel.connect 'ccc://localhost/db'
322
+ c.should be_a_kind_of(CCC)
323
+ c.opts[:host].should == 'localhost'
324
+ c.opts[:database].should == 'db'
325
+ end
326
+
327
+ specify "should be accessible through Sequel.open" do
328
+ c = Sequel.open 'ccc://localhost/db'
329
+ c.should be_a_kind_of(CCC)
330
+ c.opts[:host].should == 'localhost'
331
+ c.opts[:database].should == 'db'
332
+ end
333
+
334
+ specify "should be accessible through Sequel()" do
335
+ c = Sequel('ccc://localhost/db')
336
+ c.should be_a_kind_of(CCC)
337
+ c.opts[:host].should == 'localhost'
338
+ c.opts[:database].should == 'db'
339
+ end
340
+
341
+ end
342
+
343
+ context "An unknown database scheme" do
344
+ specify "should raise an exception in Sequel::Database.connect" do
345
+ proc {Sequel::Database.connect('ddd://localhost/db')}.should raise_error(SequelError)
346
+ end
347
+
348
+ specify "should raise an exception in Sequel.connect" do
349
+ proc {Sequel.connect('ddd://localhost/db')}.should raise_error(SequelError)
350
+ end
351
+
352
+ specify "should raise an exception in Sequel.open" do
353
+ proc {Sequel.open('ddd://localhost/db')}.should raise_error(SequelError)
354
+ end
355
+ end
356
+
357
+ context "Database#uri_to_options" do
358
+ specify "should convert a URI to an options hash" do
359
+ h = Sequel::Database.uri_to_options(URI.parse('ttt://uuu:ppp@192.168.60.1:1234/blah'))
360
+ h[:user].should == 'uuu'
361
+ h[:password].should == 'ppp'
362
+ h[:host].should == '192.168.60.1'
363
+ h[:port].should == 1234
364
+ h[:database].should == 'blah'
365
+ end
366
+ end