1
1
#!/usr/bin/env python
3
$Id: dbapi20.py,v 1.2 2003/02/12 09:48:46 zenzen Exp $
3
$Id: dbapi20.py,v 1.3 2003/02/12 22:54:38 zenzen Exp $
6
__rcs_id__ = '$Id: dbapi20.py,v 1.2 2003/02/12 09:48:46 zenzen Exp $'
7
__version__ = '$Revision: 1.2 $'[11:-2]
6
__rcs_id__ = '$Id: dbapi20.py,v 1.3 2003/02/12 22:54:38 zenzen Exp $'
7
__version__ = '$Revision: 1.3 $'[11:-2]
8
8
__author__ = 'Stuart Bishop <zen@shangri-la.dropbear.id.au>'
12
13
class test_DBAPI20:
13
14
''' Test a database self.driver for DB API 2.0 compatibility.
76
78
def test_apilevel(self):
78
81
apilevel = self.driver.apilevel
79
83
self.assertEqual(apilevel,'2.0')
80
84
except AttributeError:
81
85
self.fail("Driver doesn't define apilevel")
83
87
def test_threadsafety(self):
85
90
threadsafety = self.driver.threadsafety
91
# Must be a valid value
86
92
self.failUnless(threadsafety in (0,1,2,3))
87
93
except AttributeError:
88
94
self.fail("Driver doesn't define threadsafety")
90
96
def test_paramstyle(self):
92
99
paramstyle = self.driver.paramstyle
100
# Must be a valid value
93
101
self.failUnless(paramstyle in (
94
102
'qmark','numeric','named','format','pyformat'
150
165
cur = con.cursor()
151
166
cur.execute(self.ddl1)
152
self.assertEqual(cur.description,None)
167
self.assertEqual(cur.description,None,
168
'cursor.description should be none after executing a '
169
'statement that can return no rows (such as DDL)'
153
171
cur.execute('select name from booze')
154
self.assertEqual(len(cur.description),1)
155
self.assertEqual(len(cur.description[0]),7)
156
self.assertEqual(cur.description[0][0].lower(),'name')
157
self.failIfEqual(cur.description[0][1],self.driver.STRING)
172
self.assertEqual(len(cur.description),1,
173
'cursor.description describes too many columns'
175
self.assertEqual(len(cur.description[0]),7,
176
'cursor.description[x] tuples must have 7 elements'
178
self.assertEqual(cur.description[0][0].lower(),'name',
179
'cursor.description[x][0] must return column name'
181
self.failIfEqual(cur.description[0][1],self.driver.STRING,
182
'cursor.description[x][1] must return column type. Got %r'
183
% cur.description[0][1]
159
186
# Make sure self.description gets reset
160
187
cur.execute(self.ddl2)
161
self.assertEqual(cur.description,None)
188
self.assertEqual(cur.description,None,
189
'cursor.description not being set to None when executing '
190
'no-result statements (eg. DDL)'
168
198
cur = con.cursor()
169
199
cur.execute(self.ddl1)
170
self.assertEqual(cur.rowcount,-1)
200
self.assertEqual(cur.rowcount,-1,
201
'cursor.rowcount should be -1 after executing no-result '
171
204
cur.execute("insert into booze values ('Victoria Bitter')")
172
self.failUnless(cur.rowcount in (-1,1))
205
self.failUnless(cur.rowcount in (-1,1),
206
'cursor.rowcount should == number or rows inserted, or '
207
'set to -1 after executing an insert statement'
173
209
cur.execute("select name from booze")
174
self.failUnless(cur.rowcount in (-1,1))
210
self.failUnless(cur.rowcount in (-1,1),
211
'cursor.rowcount should == number of rows returned, or '
212
'set to -1 after executing a select statement'
175
214
cur.execute(ddl2)
176
self.assertEqual(cur.rowcount,-1)
215
self.assertEqual(cur.rowcount,-1,
216
'cursor.rowcount not being reset to -1 after executing '
217
'no-result statements'
219
269
'insert into booze values (%(beer)s)',{'beer':"Cooper's"}
222
self.fail('Unknown paramstyle')
272
self.fail('Invalid paramstyle')
223
273
cur.execute('select name from booze')
224
274
res = cur.fetchall()
225
self.assertEqual(len(res),2)
275
self.assertEqual(len(res),2,'cursor.fetchall returned too few rows')
226
276
beers = [res[0][0],res[1][0]]
228
self.assertEqual(beers[0],"Cooper's")
229
self.assertEqual(beers[1],"Victoria Bitter")
278
self.assertEqual(beers[0],"Cooper's",
279
'cursor.fetchall retrieved invalid data, or data inserted '
282
self.assertEqual(beers[1],"Victoria Bitter",
283
'cursor.fetchall retrieved invalid data, or data inserted '
231
287
def test_executemany(self):
232
288
con = self._connect()
249
305
self.fail('Unknown paramstyle')
250
306
cur.execute('select name from booze')
251
307
res = cur.fetchall()
252
self.assertEqual(len(res),2)
308
self.assertEqual(len(res),2,
309
'cursor.fetchall retrieved incorrect number of rows'
253
311
beers = [res[0][0],res[1][0]]
255
self.assertEqual(beers[0],"Boag's")
256
self.assertEqual(beers[1],"Cooper's")
313
self.assertEqual(beers[0],"Boag's",'incorrect data retrieved')
314
self.assertEqual(beers[1],"Cooper's",'incorrect data retrieved')
261
319
con = self._connect()
263
321
cur = con.cursor()
323
# cursor.fetchone should raise an Error if called before
324
# executing a select-type query
264
325
self.assertRaises(self.driver.Error,cur.fetchone)
327
# cursor.fetchone should raise an Error if called after
328
# executing a query that cannnot return rows
265
329
cur.execute(self.ddl1)
266
330
self.assertRaises(self.driver.Error,cur.fetchone)
332
# cursor.fetchone should raise an Error if called after
333
# executing a query that cannnot return rows
267
334
cur.execute("insert into booze values ('Victoria Bitter')")
268
335
self.assertRaises(self.driver.Error,cur.fetchone)
269
337
cur.execute('select name from booze')
270
338
r = cur.fetchone()
271
self.assertEqual(len(r),1)
272
self.assertEqual(r[0],'Victoria Bitter')
273
self.assertEqual(cur.fetchone(),None)
339
self.assertEqual(len(r),1,
340
'cursor.fetchone should have retrieved a single row'
342
self.assertEqual(r[0],'Victoria Bitter',
343
'cursor.fetchone retrieved incorrect data'
345
self.assertEqual(cur.fetchone(),None,
346
'cursor.fetchone should return None if no more rows available'
300
376
cur.execute('select name from booze')
301
377
r = cur.fetchmany(4) # Should get 4 rows
302
self.assertEqual(len(r),4)
378
self.assertEqual(len(r),4,
379
'cursor.fetchmany retrieved incorrect number of rows'
303
381
r = cur.fetchmany(4) # Should get 2 more
304
self.assertEqual(len(r),2)
382
self.assertEqual(len(r),2,
383
'cursor.fetchmany retrieved incorrect number of rows'
305
385
r = cur.fetchmany(4) # Should be an empty sequence
306
self.assertEqual(len(r),0)
308
cur.execute('select name from booze')
309
r = cur.fetchmany(size=4) # Should get 4 rows
310
self.assertEqual(len(r),4)
311
r = cur.fetchmany(size=1) # Should get 1 more
312
self.assertEqual(len(r),1)
313
r = cur.fetchmany(size=4) # Should get 1 more
314
self.assertEqual(len(r),1)
315
r = cur.fetchmany(size=4) # Should get an empty sequence
316
self.assertEqual(len(r),0)
386
self.assertEqual(len(r),0,
387
'cursor.fetchmany should return an empty sequence after '
388
'results are exhausted'
391
# Same as above, using cursor.arraysize
319
393
cur.execute('select name from booze')
320
394
r = cur.fetchmany() # Should get 4 rows
321
self.assertEqual(len(r),4)
395
self.assertEqual(len(r),4,
396
'cursor.arraysize not being honoured by fetchmany'
322
398
r = cur.fetchmany() # Should get 2 more
323
399
self.assertEqual(len(r),2)
324
400
r = cur.fetchmany() # Should be an empty sequence
328
404
cur.execute('select name from booze')
329
405
rows = cur.fetchmany() # Should get all rows
330
self.assertEqual(len(r),6)
331
self.assertEqual(len(r),6)
406
self.assertEqual(len(rows),6)
407
self.assertEqual(len(rows),6)
332
408
rows = [r[0] for r in rows]
335
411
# Make sure we get the right data back out
336
412
for i in range(0,6):
337
self.assertEqual(rows[i],self.samples[i])
413
self.assertEqual(rows[i],self.samples[i],
414
'incorrect data retrieved by cursor.fetchmany'
339
417
cur.execute(self.ddl2)
340
418
cur.execute('select name from barflys')
341
419
r = cur.fetchmany() # Should get empty sequence
342
self.assertEqual(len(r),0)
420
self.assertEqual(len(r),0,
421
'cursor.fetchmany should return an empty sequence if '
422
'query retrieved no rows'
348
429
con = self._connect()
350
431
cur = con.cursor()
351
self.assertRaises(self.driver.Error,cur.fetchall)
432
# cursor.fetchall should raise an Error if called
433
# without executing a query that may return rows (such
435
self.assertRaises(self.driver.Error, cur.fetchall)
353
437
for sql in self.populate:
440
# cursor.fetchall should raise an Error if called
441
# after executing a a statement that cannot return rows
355
442
self.assertRaises(self.driver.Error,cur.fetchall)
357
444
cur.execute('select name from booze')
358
445
rows = cur.fetchall()
359
self.assertEqual(len(rows),len(self.samples))
446
self.assertEqual(len(rows),len(self.samples),
447
'cursor.fetchall did not retrieve all rows'
360
449
rows = [r[0] for r in rows]
362
451
for i in range(0,len(self.samples)):
363
self.assertEqual(rows[i],self.samples[i])
452
self.assertEqual(rows[i],self.samples[i],
453
'cursor.fetchall retrieved incorrect rows'
365
456
cur.execute(self.ddl2)
366
457
cur.execute('select name from barflys')
367
458
rows = cur.fetchall()
368
self.assertEqual(len(rows),0)
459
self.assertEqual(len(rows),0,
460
'cursor.fetchall should return an empty list if '
461
'a select query returns no rows'
382
476
rows23 = cur.fetchmany(2)
383
477
rows4 = cur.fetchone()
384
478
rows56 = cur.fetchall()
385
self.assertEqual(len(rows23),2)
386
self.assertEqual(len(rows56),2)
479
self.assertEqual(len(rows23),2,
480
'fetchmany returned incorrect number of rows'
482
self.assertEqual(len(rows56),2,
483
'fetchall returned incorrect number of rows'
388
486
rows = [rows1[0]]
389
487
rows.extend([rows23[0][0],rows23[1][0]])
435
538
def test_Date(self):
436
539
d1 = self.driver.Date(2002,12,25)
437
d2 = self.driver.DateFromTicks(1040823930)
540
d2 = self.driver.DateFromTicks(time.mktime((2002,12,25,0,0,0,0,0,0)))
438
541
# Can we assume this? API doesn't specify, but it seems implied
439
self.assertEqual(str(d1),str(d2))
542
# self.assertEqual(str(d1),str(d2))
441
544
def test_Time(self):
442
545
t1 = self.driver.Time(13,45,30)
443
t2 = self.driver.TimeFromTicks(1040823930)
546
t2 = self.driver.TimeFromTicks(time.mktime((0,0,0,13,45,30,0,0,0)))
444
547
# Can we assume this? API doesn't specify, but it seems implied
445
self.assertEqual(str(t1),str(t2))
548
# self.assertEqual(str(t1),str(t2))
447
550
def test_Timestamp(self):
448
551
t1 = self.driver.Timestamp(2002,12,25,13,45,30)
449
t2 = self.driver.TimestampFromTicks(1040823930)
552
t2 = self.driver.TimestampFromTicks(
553
time.mktime((2002,12,25,13,45,30,0,0,0))
450
555
# Can we assume this? API doesn't specify, but it seems implied
451
self.assertEqual(str(t1),str(t2))
556
# self.assertEqual(str(t1),str(t2))
453
558
def test_Binary(self):
454
559
b = self.driver.Binary('Something')
455
560
b = self.driver.Binary('')
457
562
def test_STRING(self):
458
self.failUnless(hasattr(self.driver,'STRING'))
563
self.failUnless(hasattr(self.driver,'STRING'),
564
'module.STRING must be defined'
460
567
def test_BINARY(self):
461
self.failUnless(hasattr(self.driver,'BINARY'))
568
self.failUnless(hasattr(self.driver,'BINARY'),
569
'module.BINARY must be defined.'
463
572
def test_NUMBER(self):
464
self.failUnless(hasattr(self.driver,'NUMBER'))
573
self.failUnless(hasattr(self.driver,'NUMBER'),
574
'module.NUMBER must be defined.'
466
577
def test_DATETIME(self):
467
self.failUnless(hasattr(self.driver,'DATETIME'))
578
self.failUnless(hasattr(self.driver,'DATETIME'),
579
'module.DATETIME must be defined.'
469
582
def test_ROWID(self):
470
self.failUnless(hasattr(self.driver,'ROWID'))
583
self.failUnless(hasattr(self.driver,'ROWID'),
584
'module.ROWID must be defined.'