rdbi 0.9.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -94,6 +94,8 @@ module RDBI::Type
94
94
  true
95
95
  when /^(f(alse)?|0)$/i
96
96
  false
97
+ else
98
+ nil
97
99
  end
98
100
  }
99
101
  end
@@ -14,14 +14,12 @@ Gem::Specification.new do |s|
14
14
  s.email = %q{erik@hollensbe.org}
15
15
  s.extra_rdoc_files = [
16
16
  "LICENSE",
17
- "README.rdoc"
17
+ "README.txt"
18
18
  ]
19
19
  s.files = [
20
- ".document",
21
20
  "LICENSE",
22
- "README.rdoc",
21
+ "README.txt",
23
22
  "Rakefile",
24
- "VERSION",
25
23
  "docs/external-api.pdf",
26
24
  "docs/external-api.texi",
27
25
  "lib/rdbi.rb",
@@ -1,6 +1,5 @@
1
1
  require 'rubygems'
2
2
  gem 'rdbi-driver-mock'
3
- gem 'test-unit'
4
3
  require 'test/unit'
5
4
 
6
5
  $LOAD_PATH.unshift(File.dirname(__FILE__))
@@ -8,6 +7,35 @@ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
8
7
  require 'rdbi'
9
8
  require 'rdbi/driver/mock'
10
9
 
10
+ # -- Fake an exceptional statement handle
11
+ module FaultyDB
12
+ class Error < Exception; end
13
+ end
14
+
15
+ module RDBI
16
+ class Driver
17
+ class MockFaulty < RDBI::Driver
18
+ def initialize(*args)
19
+ super(MockFaulty::Database, *args)
20
+ end
21
+ end
22
+
23
+ class MockFaulty::Database < Mock::DBH
24
+ def new_statement(query)
25
+ MockFaulty::Statement.new(query, self)
26
+ end
27
+ end
28
+
29
+ class MockFaulty::Statement < Mock::STH
30
+ def execute(*binds)
31
+ raise ::FaultyDB::Error.new('Deadlocked, de-synchronized, corrupted, invalid, etc.')
32
+ end
33
+ alias :execute_modification :execute
34
+ end
35
+ end
36
+ end
37
+
38
+
11
39
  class Test::Unit::TestCase
12
40
  def mock_connect
13
41
  RDBI.connect(:Mock, :username => 'foo', :password => 'bar')
@@ -5,6 +5,10 @@ class TestDatabase < Test::Unit::TestCase
5
5
  @dbh = mock_connect
6
6
  end
7
7
 
8
+ def teardown
9
+ @dbh.disconnect
10
+ end
11
+
8
12
  def assert_transaction(count)
9
13
  in_transaction = @dbh.instance_variable_get("@in_transaction") ||
10
14
  @dbh.instance_variable_get(:@in_transaction)
@@ -38,7 +42,7 @@ class TestDatabase < Test::Unit::TestCase
38
42
  raise StandardError, "should call rollback"
39
43
  end
40
44
 
41
- assert_raises(StandardError.new("should call rollback")) do
45
+ assert_raises(StandardError) do
42
46
  @dbh.transaction do |dbh|
43
47
  assert_transaction(1)
44
48
  true
@@ -52,7 +56,7 @@ class TestDatabase < Test::Unit::TestCase
52
56
 
53
57
  @dbh.next_action = proc { |*args| true }
54
58
 
55
- assert_raises(StandardError.new("should call rollback")) do
59
+ assert_raises(StandardError) do
56
60
  @dbh.transaction do |dbh|
57
61
  assert_transaction(1)
58
62
 
@@ -206,20 +210,52 @@ class TestDatabase < Test::Unit::TestCase
206
210
  my_sth = nil
207
211
  my_res = nil
208
212
 
213
+ # ordinary execution
209
214
  @dbh.prepare("some statement") do |sth|
210
215
  assert(sth)
211
216
  assert_respond_to(sth, :execute)
212
217
  res = sth.execute
213
218
  assert(res)
214
219
  my_sth = sth
220
+ assert(! my_sth.finished?)
215
221
  end
216
222
 
217
223
  assert(my_sth.finished?)
218
224
 
219
- @dbh.execute("some statement") do |res|
220
- assert(res)
221
- assert_kind_of(RDBI::Result, res)
225
+ # and exceptional
226
+ begin
227
+ @dbh.prepare("some statement") do |sth|
228
+ assert(sth)
229
+ assert_respond_to(sth, :execute)
230
+ res = sth.execute
231
+ assert(res)
232
+ my_sth = sth
233
+ assert(! my_sth.finished?)
234
+ raise "Blam!"
235
+ end
236
+ rescue
222
237
  end
238
+
239
+ assert(my_sth.finished?)
240
+
241
+ # Database#execute &block
242
+
243
+ my_res = nil
244
+ block_ret = @dbh.execute("some statement") do |res|
245
+ my_res = res
246
+ assert(res)
247
+ assert_kind_of(RDBI::Result, res)
248
+ "BLOCK RETURN"
249
+ end
250
+
251
+ assert_kind_of(RDBI::Result, my_res)
252
+ # Result#finish implies Statement#finish, nil'ing
253
+ assert(my_res.sth.nil?,
254
+ 'Database#execute &p did not finish its Result')
255
+ assert(!block_ret.kind_of?(RDBI::Result),
256
+ 'Database#execute &block wrongly returned its Result')
257
+ assert_equal("BLOCK RETURN", block_ret,
258
+ "Database#execute &block didn't return the return value of &block")
223
259
  end
224
260
 
225
261
  def test_09_statement_allocation
@@ -239,9 +275,62 @@ class TestDatabase < Test::Unit::TestCase
239
275
  @dbh.disconnect
240
276
  end
241
277
 
242
- def teardown
278
+ def test_10_execute_finish
279
+ @dbh.execute("SELECT 1") do |res|
280
+ # noop
281
+ end
282
+ assert(@dbh.last_statement.finished?,
283
+ "#execute() block did not finish implicit sth")
284
+
285
+ res = @dbh.execute("SELECT 2")
286
+ assert(!@dbh.last_statement.finished?,
287
+ "#execute() unexpectedly finished implicit sth")
288
+ assert_nothing_raised do
289
+ res.finish
290
+ @dbh.disconnect
291
+ end
292
+
293
+ @dbh = RDBI.connect(:MockFaulty, :user => 'u', :pass => 'p')
294
+ assert_raises(FaultyDB::Error) do
295
+ @dbh.execute("ignored") do |not_reached|
296
+ assert(false, "A block not supposed to be reached was executed")
297
+ end
298
+ end
299
+ assert(@dbh.last_statement.finished?,
300
+ "Failed execute() &block did not finish statement")
301
+
302
+ assert_raises(FaultyDB::Error) do
303
+ res = @dbh.execute("ignored")
304
+ res.finish # Not reached
305
+ end
306
+ assert(@dbh.last_statement.finished?,
307
+ "Failed execute() did not finish statement")
308
+ end
309
+
310
+ def test_11_execute_mod_finish
311
+ @dbh.execute_modification("DROP SCHEMA INFORMATION_SCHEMA")
312
+ assert(@dbh.last_statement.finished?,
313
+ "#execute_modification() did not finish implicit sth")
314
+
315
+ a = nil
316
+ @dbh.execute_modification("IGNORED!") do |*blah|
317
+ a = "Not nil - but this block is not executed"
318
+ end
319
+
320
+ assert(a.nil?, "#execute_modification() invoked a block unexpectedly")
321
+ assert(@dbh.last_statement.finished?,
322
+ "#execute_modification() &ignored_block did not finish implicit sth")
323
+
243
324
  @dbh.disconnect
325
+
326
+ @dbh = RDBI.connect(:MockFaulty, :user => 'u', :pass => 'p')
327
+ assert_raises(FaultyDB::Error) do
328
+ count = @dbh.execute_modification("ignored")
329
+ end
330
+ assert(@dbh.last_statement.finished?,
331
+ "Failed execute_modification() did not finish statement")
244
332
  end
333
+
245
334
  end
246
335
 
247
336
  # vim: syntax=ruby ts=2 et sw=2 sts=2
@@ -20,7 +20,7 @@ class TestPool < Test::Unit::TestCase
20
20
 
21
21
  def test_03_pooling!
22
22
  pool = create_pool(:test_03)
23
- assert_raise(ArgumentError.new("too many handles in this pool (max: 5)")) do
23
+ assert_raise(ArgumentError) do
24
24
  6.times do
25
25
  RDBI::Pool[:test_03].add_connection
26
26
  end
@@ -160,7 +160,7 @@ class TestPool < Test::Unit::TestCase
160
160
  assert_kind_of(RDBI::Pool, pool)
161
161
  end
162
162
 
163
- assert(10, count)
163
+ assert_equal(10, count)
164
164
  assert_respond_to(RDBI::Pool, :map)
165
165
 
166
166
  pool = create_pool(:test_08)
@@ -182,6 +182,15 @@ class TestPool < Test::Unit::TestCase
182
182
 
183
183
  assert_respond_to(pool, :map)
184
184
  end
185
+
186
+ def test_09_alternative_connect_syntax
187
+ pool = RDBI::Pool.new("connections!", { :driver => :Mock, :database => ":memory:", :username => "foo" })
188
+ dbh = pool.get_dbh
189
+ assert(dbh)
190
+ assert_kind_of(RDBI::Database, dbh)
191
+
192
+ assert_equal([:Mock, { :database => ":memory:", :username => "foo" }], pool.instance_variable_get(:@connect_args))
193
+ end
185
194
  end
186
195
 
187
196
  # vim: syntax=ruby ts=2 et sw=2 sts=2
@@ -16,7 +16,7 @@ class TestRDBI < Test::Unit::TestCase
16
16
 
17
17
  assert_raise(ArgumentError) { RDBI.connect(1, :user => :blah) }
18
18
 
19
- assert_nothing_raised { dbh = RDBI.connect(:Mock) }
19
+ assert_raise(ArgumentError) { dbh = RDBI.connect(:Mock) }
20
20
  end
21
21
 
22
22
  def test_02_last_dbh
@@ -63,6 +63,59 @@ class TestRDBI < Test::Unit::TestCase
63
63
  dbh = RDBI.connect_cached(:Mock, :username => :foo, :pool_name => :test_05)
64
64
  assert_equal(RDBI.pool(:test_05).handles[0], dbh)
65
65
  end
66
+
67
+ def test_06_connect_block
68
+ my_dbh = nil
69
+
70
+ # Ordinary operation
71
+ RDBI.connect(:Mock, :username => :foo, :password => :bar) do |dbh|
72
+ assert(dbh)
73
+ assert_kind_of(RDBI::Database, dbh)
74
+ my_dbh = dbh
75
+ assert(my_dbh.connected?)
76
+ end
77
+ assert(! my_dbh.connected?)
78
+
79
+ # and exceptional operation
80
+ begin
81
+ RDBI.connect(:Mock, :username => :foo, :password => :bar) do |dbh|
82
+ assert(dbh)
83
+ assert_kind_of(RDBI::Database, dbh)
84
+ my_dbh = dbh
85
+ assert(my_dbh.connected?)
86
+ raise "Blam!"
87
+ end
88
+ rescue
89
+ end
90
+ assert(! my_dbh.connected?)
91
+ end
92
+
93
+ def test_07_connect_cached_block
94
+ conn_args = [:Mock, {:username => :foo, :password => :bar}]
95
+ my_dbh = nil
96
+
97
+ # Ordinary operation
98
+ RDBI.connect_cached(*conn_args) do |dbh|
99
+ assert(dbh)
100
+ assert_kind_of(RDBI::Database, dbh)
101
+ my_dbh = dbh
102
+ assert(my_dbh.connected?)
103
+ end
104
+ assert(my_dbh.connected?)
105
+
106
+ # and exceptional operation
107
+ begin
108
+ RDBI.connect_cached(*conn_args) do |dbh|
109
+ assert(dbh)
110
+ assert_kind_of(RDBI::Database, dbh)
111
+ my_dbh = dbh
112
+ assert(my_dbh.connected?)
113
+ raise "Blam!"
114
+ end
115
+ rescue
116
+ end
117
+ assert(my_dbh.connected?)
118
+ end
66
119
  end
67
120
 
68
121
  # vim: syntax=ruby ts=2 et sw=2 sts=2
@@ -15,21 +15,34 @@ class TestResult < Test::Unit::TestCase
15
15
 
16
16
  def mock_result
17
17
  names = [:zero, :one, :two]
18
- res = RDBI::Result.new(@dbh.prepare("foo"), [1], generate_data, RDBI::Schema.new((0..2).to_a.map { |x| RDBI::Column.new(names[x], :integer, :default) }), { :default => RDBI::Type.filterlist() })
18
+ res = RDBI::Result.new(
19
+ @dbh.prepare("foo"),
20
+ [1],
21
+ generate_data,
22
+ RDBI::Schema.new((0..2).to_a.map { |x| RDBI::Column.new(names[x], :integer, :default) }),
23
+ { :default => RDBI::Type.filterlist() }
24
+ )
19
25
  end
20
26
 
21
27
  def mock_empty_result
22
28
  names = [:zero, :one, :two]
23
- res = RDBI::Result.new(@dbh.prepare("foo"), [1], RDBI::Driver::Mock::Cursor.new([]), RDBI::Schema.new((0..2).to_a.map { |x| RDBI::Column.new(names[x], :integer, :default) }), { :default => RDBI::Type.filterlist() })
29
+ res = RDBI::Result.new(
30
+ @dbh.prepare("foo"),
31
+ [1],
32
+ RDBI::Driver::Mock::Cursor.new([]),
33
+ RDBI::Schema.new((0..2).to_a.map { |x| RDBI::Column.new(names[x], :integer, :default) }),
34
+ { :default => RDBI::Type.filterlist() }
35
+ )
24
36
  end
25
37
 
26
38
  def get_index(res)
27
- get_guts(get_guts(res)[:data])[:index]
39
+ cursor = get_guts(res)[:data]
40
+ cursor.instance_variable_get("@index") || res.instance_variable_get(:@index)
28
41
  end
29
42
 
30
43
  def get_guts(res)
31
44
  h = { }
32
- %W[index schema binds sth data].collect(&:to_sym).each do |sym|
45
+ %W[schema binds sth data].collect(&:to_sym).each do |sym|
33
46
  h[sym] = res.instance_variable_get("@#{sym}") || res.instance_variable_get("@#{sym}".to_sym)
34
47
  end
35
48
 
@@ -76,10 +89,9 @@ class TestResult < Test::Unit::TestCase
76
89
  as
77
90
  fetch
78
91
  read
79
- raw_fetch
80
- finish
92
+ finish
81
93
  ].collect(&:to_sym).each do |sym|
82
- assert_respond_to(res, sym)
94
+ assert_respond_to(res, sym, "#{res.class} did not respond to :#{sym}")
83
95
  end
84
96
 
85
97
  res.sth.finish
@@ -299,6 +311,116 @@ class TestResult < Test::Unit::TestCase
299
311
  assert_equal({:zero=>-1, :one=>0, :two=>1}, YAML.load(res.as(:YAML).first))
300
312
  assert_equal({:zero=>8, :one=>9, :two=>10}, YAML.load(res.as(:YAML).last))
301
313
  end
314
+
315
+ def test_13_enumerable_as
316
+ # 'master' dab6270 branch (0.9.1+) returned a Result::Driver for as()
317
+
318
+ res = mock_result
319
+
320
+ i = -1
321
+ # Mock result set is:
322
+ #
323
+ # ZERO ONE TWO
324
+ # ==== === ===
325
+ # -1 0 1
326
+ # 0 1 2
327
+ # 1 2 3
328
+ # ...
329
+ # 8 9 10
330
+ #
331
+ res.as(:Struct).each do |row|
332
+ assert_kind_of(::Struct, row)
333
+ assert_equal([i, i+1, i+2], [row.zero, row.one, row.two])
334
+ i += 1
335
+ end
336
+ res.sth.finish
337
+ end
338
+
339
+ def test_14_results_driven_struct
340
+ # 'master' dab6270 branch (0.9.1+) returned 'raw' rows for #each,
341
+ # #first and #last
342
+
343
+ res = mock_result
344
+
345
+ res.as(:Struct)
346
+ row = res.first # does not advance underlying index
347
+ assert_kind_of(::Struct, row)
348
+ assert_equal([-1, 0, 1], [row.zero, row.one, row.two])
349
+
350
+ res.each do |r|
351
+ assert_kind_of(::Struct, r)
352
+ assert_equal([-1, 0, 1], [r.zero, r.one, r.two])
353
+ break # Just one row, thank you
354
+ end
355
+
356
+ row = res.last
357
+ assert_kind_of(::Struct, row)
358
+ assert_equal([8, 9, 10], [row.zero, row.one, row.two])
359
+
360
+ res.sth.finish
361
+ end
362
+
363
+ def test_15_results_driven_csv
364
+ # 'master' 20917a3 branch (pilcrow/result-as) didn't handle
365
+ # eof properly for result drivers that didn't return sets of
366
+ # rows as an array of rows
367
+
368
+ res = mock_result
369
+
370
+ res.as(:CSV)
371
+ row = res.first # does not advance underlying index
372
+ assert_equal("-1,0,1\n", row)
373
+
374
+ res.each do |r|
375
+ assert_equal("-1,0,1\n", r)
376
+ break # Just one row, thank you
377
+ end
378
+
379
+ row = res.last
380
+ assert_equal("8,9,10\n", row)
381
+
382
+ res.sth.finish
383
+ end
384
+
385
+ def test_16_results_driven_yaml
386
+ # As for test_15, but with YAML
387
+ # 'master' 20917a3 branch (pilcrow/result-as) didn't handle
388
+ # eof properly for result drivers that didn't return sets of
389
+ # rows as an array of rows
390
+
391
+ res = mock_result
392
+
393
+ res.as(:YAML)
394
+ row = res.first # does not advance underlying index
395
+ assert_equal({:zero=>-1, :one=>0, :two=>1}, YAML.load(row))
396
+
397
+ res.each do |r|
398
+ assert_equal({:zero=>-1, :one=>0, :two=>1}, YAML.load(r))
399
+ break # Just one row, thank you
400
+ end
401
+
402
+ row = res.last
403
+ assert_equal({:zero=>8, :one=>9, :two=>10}, YAML.load(row))
404
+
405
+ res.sth.finish
406
+ end
407
+
408
+ def test_17_results_as_empty
409
+ [:Array, :Struct, :YAML, :CSV].each do |rd|
410
+ res = mock_empty_result
411
+ res.as(rd).each do |not_reached|
412
+ assert(false, "each block unexpectedly reached during :#{rd} test")
413
+ end
414
+ res.sth.finish
415
+
416
+ res = mock_empty_result
417
+ res.as(rd)
418
+ assert_nil(res.first, "#first was not nil on empty result set")
419
+ assert_nil(res.last, "#last was not nil on empty result set")
420
+ res.sth.finish
421
+ end
422
+ end
423
+
302
424
  end
303
425
 
304
426
  # vim: syntax=ruby ts=2 et sw=2 sts=2