sequel 0.1.7 → 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -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