comparison tests/dbapi20.py @ 18:d55bfb1a4701 MySQLdb

Tons of changes from major refactoring/cleanup. This is all really broken right now. In particular, all results are returned as strings.
author adustman
date Fri, 14 Mar 2008 23:06:29 +0000
parents
children
comparison
equal deleted inserted replaced
17:7c7a89123d65 18:d55bfb1a4701
1 #!/usr/bin/env python
2 ''' Python DB API 2.0 driver compliance unit test suite.
3
4 This software is Public Domain and may be used without restrictions.
5
6 "Now we have booze and barflies entering the discussion, plus rumours of
7 DBAs on drugs... and I won't tell you what flashes through my mind each
8 time I read the subject line with 'Anal Compliance' in it. All around
9 this is turning out to be a thoroughly unwholesome unit test."
10
11 -- Ian Bicking
12 '''
13
14 __rcs_id__ = '$Id$'
15 __version__ = '$Revision$'[11:-2]
16 __author__ = 'Stuart Bishop <[email protected]>'
17
18 import unittest
19 import time
20
21 # $Log$
22 # Revision 1.1.2.1 2006/02/25 03:44:32 adustman
23 # Generic DB-API unit test module
24 #
25 # Revision 1.10 2003/10/09 03:14:14 zenzen
26 # Add test for DB API 2.0 optional extension, where database exceptions
27 # are exposed as attributes on the Connection object.
28 #
29 # Revision 1.9 2003/08/13 01:16:36 zenzen
30 # Minor tweak from Stefan Fleiter
31 #
32 # Revision 1.8 2003/04/10 00:13:25 zenzen
33 # Changes, as per suggestions by M.-A. Lemburg
34 # - Add a table prefix, to ensure namespace collisions can always be avoided
35 #
36 # Revision 1.7 2003/02/26 23:33:37 zenzen
37 # Break out DDL into helper functions, as per request by David Rushby
38 #
39 # Revision 1.6 2003/02/21 03:04:33 zenzen
40 # Stuff from Henrik Ekelund:
41 # added test_None
42 # added test_nextset & hooks
43 #
44 # Revision 1.5 2003/02/17 22:08:43 zenzen
45 # Implement suggestions and code from Henrik Eklund - test that cursor.arraysize
46 # defaults to 1 & generic cursor.callproc test added
47 #
48 # Revision 1.4 2003/02/15 00:16:33 zenzen
49 # Changes, as per suggestions and bug reports by M.-A. Lemburg,
50 # Matthew T. Kromer, Federico Di Gregorio and Daniel Dittmar
51 # - Class renamed
52 # - Now a subclass of TestCase, to avoid requiring the driver stub
53 # to use multiple inheritance
54 # - Reversed the polarity of buggy test in test_description
55 # - Test exception heirarchy correctly
56 # - self.populate is now self._populate(), so if a driver stub
57 # overrides self.ddl1 this change propogates
58 # - VARCHAR columns now have a width, which will hopefully make the
59 # DDL even more portible (this will be reversed if it causes more problems)
60 # - cursor.rowcount being checked after various execute and fetchXXX methods
61 # - Check for fetchall and fetchmany returning empty lists after results
62 # are exhausted (already checking for empty lists if select retrieved
63 # nothing
64 # - Fix bugs in test_setoutputsize_basic and test_setinputsizes
65 #
66
67 class DatabaseAPI20Test(unittest.TestCase):
68 ''' Test a database self.driver for DB API 2.0 compatibility.
69 This implementation tests Gadfly, but the TestCase
70 is structured so that other self.drivers can subclass this
71 test case to ensure compiliance with the DB-API. It is
72 expected that this TestCase may be expanded in the future
73 if ambiguities or edge conditions are discovered.
74
75 The 'Optional Extensions' are not yet being tested.
76
77 self.drivers should subclass this test, overriding setUp, tearDown,
78 self.driver, connect_args and connect_kw_args. Class specification
79 should be as follows:
80
81 import dbapi20
82 class mytest(dbapi20.DatabaseAPI20Test):
83 [...]
84
85 Don't 'import DatabaseAPI20Test from dbapi20', or you will
86 confuse the unit tester - just 'import dbapi20'.
87 '''
88
89 # The self.driver module. This should be the module where the 'connect'
90 # method is to be found
91 driver = None
92 connect_args = () # List of arguments to pass to connect
93 connect_kw_args = {} # Keyword arguments for connect
94 table_prefix = 'dbapi20test_' # If you need to specify a prefix for tables
95
96 ddl1 = 'create table %sbooze (name varchar(20))' % table_prefix
97 ddl2 = 'create table %sbarflys (name varchar(20))' % table_prefix
98 xddl1 = 'drop table %sbooze' % table_prefix
99 xddl2 = 'drop table %sbarflys' % table_prefix
100
101 lowerfunc = 'lower' # Name of stored procedure to convert string->lowercase
102
103 # Some drivers may need to override these helpers, for example adding
104 # a 'commit' after the execute.
105 def executeDDL1(self,cursor):
106 cursor.execute(self.ddl1)
107
108 def executeDDL2(self,cursor):
109 cursor.execute(self.ddl2)
110
111 def setUp(self):
112 ''' self.drivers should override this method to perform required setup
113 if any is necessary, such as creating the database.
114 '''
115 pass
116
117 def tearDown(self):
118 ''' self.drivers should override this method to perform required cleanup
119 if any is necessary, such as deleting the test database.
120 The default drops the tables that may be created.
121 '''
122 con = self._connect()
123 try:
124 cur = con.cursor()
125 for ddl in (self.xddl1,self.xddl2):
126 try:
127 cur.execute(ddl)
128 con.commit()
129 except self.driver.Error:
130 # Assume table didn't exist. Other tests will check if
131 # execute is busted.
132 pass
133 finally:
134 con.close()
135
136 def _connect(self):
137 try:
138 return self.driver.connect(
139 *self.connect_args,**self.connect_kw_args
140 )
141 except AttributeError:
142 self.fail("No connect method found in self.driver module")
143
144 def test_connect(self):
145 con = self._connect()
146 con.close()
147
148 def test_apilevel(self):
149 try:
150 # Must exist
151 apilevel = self.driver.apilevel
152 # Must equal 2.0
153 self.assertEqual(apilevel,'2.0')
154 except AttributeError:
155 self.fail("Driver doesn't define apilevel")
156
157 def test_threadsafety(self):
158 try:
159 # Must exist
160 threadsafety = self.driver.threadsafety
161 # Must be a valid value
162 self.failUnless(threadsafety in (0,1,2,3))
163 except AttributeError:
164 self.fail("Driver doesn't define threadsafety")
165
166 def test_paramstyle(self):
167 try:
168 # Must exist
169 paramstyle = self.driver.paramstyle
170 # Must be a valid value
171 self.failUnless(paramstyle in (
172 'qmark','numeric','named','format','pyformat'
173 ))
174 except AttributeError:
175 self.fail("Driver doesn't define paramstyle")
176
177 def test_Exceptions(self):
178 # Make sure required exceptions exist, and are in the
179 # defined heirarchy.
180 self.failUnless(issubclass(self.driver.Warning,StandardError))
181 self.failUnless(issubclass(self.driver.Error,StandardError))
182 self.failUnless(
183 issubclass(self.driver.InterfaceError,self.driver.Error)
184 )
185 self.failUnless(
186 issubclass(self.driver.DatabaseError,self.driver.Error)
187 )
188 self.failUnless(
189 issubclass(self.driver.OperationalError,self.driver.Error)
190 )
191 self.failUnless(
192 issubclass(self.driver.IntegrityError,self.driver.Error)
193 )
194 self.failUnless(
195 issubclass(self.driver.InternalError,self.driver.Error)
196 )
197 self.failUnless(
198 issubclass(self.driver.ProgrammingError,self.driver.Error)
199 )
200 self.failUnless(
201 issubclass(self.driver.NotSupportedError,self.driver.Error)
202 )
203
204 def test_ExceptionsAsConnectionAttributes(self):
205 # OPTIONAL EXTENSION
206 # Test for the optional DB API 2.0 extension, where the exceptions
207 # are exposed as attributes on the Connection object
208 # I figure this optional extension will be implemented by any
209 # driver author who is using this test suite, so it is enabled
210 # by default.
211 con = self._connect()
212 drv = self.driver
213 self.failUnless(con.Warning is drv.Warning)
214 self.failUnless(con.Error is drv.Error)
215 self.failUnless(con.InterfaceError is drv.InterfaceError)
216 self.failUnless(con.DatabaseError is drv.DatabaseError)
217 self.failUnless(con.OperationalError is drv.OperationalError)
218 self.failUnless(con.IntegrityError is drv.IntegrityError)
219 self.failUnless(con.InternalError is drv.InternalError)
220 self.failUnless(con.ProgrammingError is drv.ProgrammingError)
221 self.failUnless(con.NotSupportedError is drv.NotSupportedError)
222
223
224 def test_commit(self):
225 con = self._connect()
226 try:
227 # Commit must work, even if it doesn't do anything
228 con.commit()
229 finally:
230 con.close()
231
232 def test_rollback(self):
233 con = self._connect()
234 # If rollback is defined, it should either work or throw
235 # the documented exception
236 if hasattr(con,'rollback'):
237 try:
238 con.rollback()
239 except self.driver.NotSupportedError:
240 pass
241
242 def test_cursor(self):
243 con = self._connect()
244 try:
245 cur = con.cursor()
246 finally:
247 con.close()
248
249 def test_cursor_isolation(self):
250 con = self._connect()
251 try:
252 # Make sure cursors created from the same connection have
253 # the documented transaction isolation level
254 cur1 = con.cursor()
255 cur2 = con.cursor()
256 self.executeDDL1(cur1)
257 cur1.execute("insert into %sbooze values ('Victoria Bitter')" % (
258 self.table_prefix
259 ))
260 cur2.execute("select name from %sbooze" % self.table_prefix)
261 booze = cur2.fetchall()
262 self.assertEqual(len(booze),1)
263 self.assertEqual(len(booze[0]),1)
264 self.assertEqual(booze[0][0],'Victoria Bitter')
265 finally:
266 con.close()
267
268 def test_description(self):
269 con = self._connect()
270 try:
271 cur = con.cursor()
272 self.executeDDL1(cur)
273 self.assertEqual(cur.description,None,
274 'cursor.description should be none after executing a '
275 'statement that can return no rows (such as DDL)'
276 )
277 cur.execute('select name from %sbooze' % self.table_prefix)
278 self.assertEqual(len(cur.description),1,
279 'cursor.description describes too many columns'
280 )
281 self.assertEqual(len(cur.description[0]),7,
282 'cursor.description[x] tuples must have 7 elements'
283 )
284 self.assertEqual(cur.description[0][0].lower(),'name',
285 'cursor.description[x][0] must return column name'
286 )
287 self.assertEqual(cur.description[0][1],self.driver.STRING,
288 'cursor.description[x][1] must return column type. Got %r'
289 % cur.description[0][1]
290 )
291
292 # Make sure self.description gets reset
293 self.executeDDL2(cur)
294 self.assertEqual(cur.description,None,
295 'cursor.description not being set to None when executing '
296 'no-result statements (eg. DDL)'
297 )
298 finally:
299 con.close()
300
301 def test_rowcount(self):
302 con = self._connect()
303 try:
304 cur = con.cursor()
305 self.executeDDL1(cur)
306 self.assertEqual(cur.rowcount,-1,
307 'cursor.rowcount should be -1 after executing no-result '
308 'statements'
309 )
310 cur.execute("insert into %sbooze values ('Victoria Bitter')" % (
311 self.table_prefix
312 ))
313 self.failUnless(cur.rowcount in (-1,1),
314 'cursor.rowcount should == number or rows inserted, or '
315 'set to -1 after executing an insert statement'
316 )
317 cur.execute("select name from %sbooze" % self.table_prefix)
318 self.failUnless(cur.rowcount in (-1,1),
319 'cursor.rowcount should == number of rows returned, or '
320 'set to -1 after executing a select statement'
321 )
322 self.executeDDL2(cur)
323 self.assertEqual(cur.rowcount,-1,
324 'cursor.rowcount not being reset to -1 after executing '
325 'no-result statements'
326 )
327 finally:
328 con.close()
329
330 lower_func = 'lower'
331 def test_callproc(self):
332 con = self._connect()
333 try:
334 cur = con.cursor()
335 if self.lower_func and hasattr(cur,'callproc'):
336 r = cur.callproc(self.lower_func,('FOO',))
337 self.assertEqual(len(r),1)
338 self.assertEqual(r[0],'FOO')
339 r = cur.fetchall()
340 self.assertEqual(len(r),1,'callproc produced no result set')
341 self.assertEqual(len(r[0]),1,
342 'callproc produced invalid result set'
343 )
344 self.assertEqual(r[0][0],'foo',
345 'callproc produced invalid results'
346 )
347 finally:
348 con.close()
349
350 def test_close(self):
351 con = self._connect()
352 try:
353 cur = con.cursor()
354 finally:
355 con.close()
356
357 # cursor.execute should raise an Error if called after connection
358 # closed
359 self.assertRaises(self.driver.Error,self.executeDDL1,cur)
360
361 # connection.commit should raise an Error if called after connection'
362 # closed.'
363 self.assertRaises(self.driver.Error,con.commit)
364
365 # connection.close should raise an Error if called more than once
366 self.assertRaises(self.driver.Error,con.close)
367
368 def test_execute(self):
369 con = self._connect()
370 try:
371 cur = con.cursor()
372 self._paraminsert(cur)
373 finally:
374 con.close()
375
376 def _paraminsert(self,cur):
377 self.executeDDL1(cur)
378 cur.execute("insert into %sbooze values ('Victoria Bitter')" % (
379 self.table_prefix
380 ))
381 self.failUnless(cur.rowcount in (-1,1))
382
383 if self.driver.paramstyle == 'qmark':
384 cur.execute(
385 'insert into %sbooze values (?)' % self.table_prefix,
386 ("Cooper's",)
387 )
388 elif self.driver.paramstyle == 'numeric':
389 cur.execute(
390 'insert into %sbooze values (:1)' % self.table_prefix,
391 ("Cooper's",)
392 )
393 elif self.driver.paramstyle == 'named':
394 cur.execute(
395 'insert into %sbooze values (:beer)' % self.table_prefix,
396 {'beer':"Cooper's"}
397 )
398 elif self.driver.paramstyle == 'format':
399 cur.execute(
400 'insert into %sbooze values (%%s)' % self.table_prefix,
401 ("Cooper's",)
402 )
403 elif self.driver.paramstyle == 'pyformat':
404 cur.execute(
405 'insert into %sbooze values (%%(beer)s)' % self.table_prefix,
406 {'beer':"Cooper's"}
407 )
408 else:
409 self.fail('Invalid paramstyle')
410 self.failUnless(cur.rowcount in (-1,1))
411
412 cur.execute('select name from %sbooze' % self.table_prefix)
413 res = cur.fetchall()
414 self.assertEqual(len(res),2,'cursor.fetchall returned too few rows')
415 beers = [res[0][0],res[1][0]]
416 beers.sort()
417 self.assertEqual(beers[0],"Cooper's",
418 'cursor.fetchall retrieved incorrect data, or data inserted '
419 'incorrectly'
420 )
421 self.assertEqual(beers[1],"Victoria Bitter",
422 'cursor.fetchall retrieved incorrect data, or data inserted '
423 'incorrectly'
424 )
425
426 def test_executemany(self):
427 con = self._connect()
428 try:
429 cur = con.cursor()
430 self.executeDDL1(cur)
431 largs = [ ("Cooper's",) , ("Boag's",) ]
432 margs = [ {'beer': "Cooper's"}, {'beer': "Boag's"} ]
433 if self.driver.paramstyle == 'qmark':
434 cur.executemany(
435 'insert into %sbooze values (?)' % self.table_prefix,
436 largs
437 )
438 elif self.driver.paramstyle == 'numeric':
439 cur.executemany(
440 'insert into %sbooze values (:1)' % self.table_prefix,
441 largs
442 )
443 elif self.driver.paramstyle == 'named':
444 cur.executemany(
445 'insert into %sbooze values (:beer)' % self.table_prefix,
446 margs
447 )
448 elif self.driver.paramstyle == 'format':
449 cur.executemany(
450 'insert into %sbooze values (%%s)' % self.table_prefix,
451 largs
452 )
453 elif self.driver.paramstyle == 'pyformat':
454 cur.executemany(
455 'insert into %sbooze values (%%(beer)s)' % (
456 self.table_prefix
457 ),
458 margs
459 )
460 else:
461 self.fail('Unknown paramstyle')
462 self.failUnless(cur.rowcount in (-1,2),
463 'insert using cursor.executemany set cursor.rowcount to '
464 'incorrect value %r' % cur.rowcount
465 )
466 cur.execute('select name from %sbooze' % self.table_prefix)
467 res = cur.fetchall()
468 self.assertEqual(len(res),2,
469 'cursor.fetchall retrieved incorrect number of rows'
470 )
471 beers = [res[0][0],res[1][0]]
472 beers.sort()
473 self.assertEqual(beers[0],"Boag's",'incorrect data retrieved')
474 self.assertEqual(beers[1],"Cooper's",'incorrect data retrieved')
475 finally:
476 con.close()
477
478 def test_fetchone(self):
479 con = self._connect()
480 try:
481 cur = con.cursor()
482
483 # cursor.fetchone should raise an Error if called before
484 # executing a select-type query
485 self.assertRaises(self.driver.Error,cur.fetchone)
486
487 # cursor.fetchone should raise an Error if called after
488 # executing a query that cannnot return rows
489 self.executeDDL1(cur)
490 self.assertRaises(self.driver.Error,cur.fetchone)
491
492 cur.execute('select name from %sbooze' % self.table_prefix)
493 self.assertEqual(cur.fetchone(),None,
494 'cursor.fetchone should return None if a query retrieves '
495 'no rows'
496 )
497 self.failUnless(cur.rowcount in (-1,0))
498
499 # cursor.fetchone should raise an Error if called after
500 # executing a query that cannnot return rows
501 cur.execute("insert into %sbooze values ('Victoria Bitter')" % (
502 self.table_prefix
503 ))
504 self.assertRaises(self.driver.Error,cur.fetchone)
505
506 cur.execute('select name from %sbooze' % self.table_prefix)
507 r = cur.fetchone()
508 self.assertEqual(len(r),1,
509 'cursor.fetchone should have retrieved a single row'
510 )
511 self.assertEqual(r[0],'Victoria Bitter',
512 'cursor.fetchone retrieved incorrect data'
513 )
514 self.assertEqual(cur.fetchone(),None,
515 'cursor.fetchone should return None if no more rows available'
516 )
517 self.failUnless(cur.rowcount in (-1,1))
518 finally:
519 con.close()
520
521 samples = [
522 'Carlton Cold',
523 'Carlton Draft',
524 'Mountain Goat',
525 'Redback',
526 'Victoria Bitter',
527 'XXXX'
528 ]
529
530 def _populate(self):
531 ''' Return a list of sql commands to setup the DB for the fetch
532 tests.
533 '''
534 populate = [
535 "insert into %sbooze values ('%s')" % (self.table_prefix,s)
536 for s in self.samples
537 ]
538 return populate
539
540 def test_fetchmany(self):
541 con = self._connect()
542 try:
543 cur = con.cursor()
544
545 # cursor.fetchmany should raise an Error if called without
546 #issuing a query
547 self.assertRaises(self.driver.Error,cur.fetchmany,4)
548
549 self.executeDDL1(cur)
550 for sql in self._populate():
551 cur.execute(sql)
552
553 cur.execute('select name from %sbooze' % self.table_prefix)
554 r = cur.fetchmany()
555 self.assertEqual(len(r),1,
556 'cursor.fetchmany retrieved incorrect number of rows, '
557 'default of arraysize is one.'
558 )
559 cur.arraysize=10
560 r = cur.fetchmany(3) # Should get 3 rows
561 self.assertEqual(len(r),3,
562 'cursor.fetchmany retrieved incorrect number of rows'
563 )
564 r = cur.fetchmany(4) # Should get 2 more
565 self.assertEqual(len(r),2,
566 'cursor.fetchmany retrieved incorrect number of rows'
567 )
568 r = cur.fetchmany(4) # Should be an empty sequence
569 self.assertEqual(len(r),0,
570 'cursor.fetchmany should return an empty sequence after '
571 'results are exhausted'
572 )
573 self.failUnless(cur.rowcount in (-1,6))
574
575 # Same as above, using cursor.arraysize
576 cur.arraysize=4
577 cur.execute('select name from %sbooze' % self.table_prefix)
578 r = cur.fetchmany() # Should get 4 rows
579 self.assertEqual(len(r),4,
580 'cursor.arraysize not being honoured by fetchmany'
581 )
582 r = cur.fetchmany() # Should get 2 more
583 self.assertEqual(len(r),2)
584 r = cur.fetchmany() # Should be an empty sequence
585 self.assertEqual(len(r),0)
586 self.failUnless(cur.rowcount in (-1,6))
587
588 cur.arraysize=6
589 cur.execute('select name from %sbooze' % self.table_prefix)
590 rows = cur.fetchmany() # Should get all rows
591 self.failUnless(cur.rowcount in (-1,6))
592 self.assertEqual(len(rows),6)
593 self.assertEqual(len(rows),6)
594 rows = [r[0] for r in rows]
595 rows.sort()
596
597 # Make sure we get the right data back out
598 for i in range(0,6):
599 self.assertEqual(rows[i],self.samples[i],
600 'incorrect data retrieved by cursor.fetchmany'
601 )
602
603 rows = cur.fetchmany() # Should return an empty list
604 self.assertEqual(len(rows),0,
605 'cursor.fetchmany should return an empty sequence if '
606 'called after the whole result set has been fetched'
607 )
608 self.failUnless(cur.rowcount in (-1,6))
609
610 self.executeDDL2(cur)
611 cur.execute('select name from %sbarflys' % self.table_prefix)
612 r = cur.fetchmany() # Should get empty sequence
613 self.assertEqual(len(r),0,
614 'cursor.fetchmany should return an empty sequence if '
615 'query retrieved no rows'
616 )
617 self.failUnless(cur.rowcount in (-1,0))
618
619 finally:
620 con.close()
621
622 def test_fetchall(self):
623 con = self._connect()
624 try:
625 cur = con.cursor()
626 # cursor.fetchall should raise an Error if called
627 # without executing a query that may return rows (such
628 # as a select)
629 self.assertRaises(self.driver.Error, cur.fetchall)
630
631 self.executeDDL1(cur)
632 for sql in self._populate():
633 cur.execute(sql)
634
635 # cursor.fetchall should raise an Error if called
636 # after executing a a statement that cannot return rows
637 self.assertRaises(self.driver.Error,cur.fetchall)
638
639 cur.execute('select name from %sbooze' % self.table_prefix)
640 rows = cur.fetchall()
641 self.failUnless(cur.rowcount in (-1,len(self.samples)))
642 self.assertEqual(len(rows),len(self.samples),
643 'cursor.fetchall did not retrieve all rows'
644 )
645 rows = [r[0] for r in rows]
646 rows.sort()
647 for i in range(0,len(self.samples)):
648 self.assertEqual(rows[i],self.samples[i],
649 'cursor.fetchall retrieved incorrect rows'
650 )
651 rows = cur.fetchall()
652 self.assertEqual(
653 len(rows),0,
654 'cursor.fetchall should return an empty list if called '
655 'after the whole result set has been fetched'
656 )
657 self.failUnless(cur.rowcount in (-1,len(self.samples)))
658
659 self.executeDDL2(cur)
660 cur.execute('select name from %sbarflys' % self.table_prefix)
661 rows = cur.fetchall()
662 self.failUnless(cur.rowcount in (-1,0))
663 self.assertEqual(len(rows),0,
664 'cursor.fetchall should return an empty list if '
665 'a select query returns no rows'
666 )
667
668 finally:
669 con.close()
670
671 def test_mixedfetch(self):
672 con = self._connect()
673 try:
674 cur = con.cursor()
675 self.executeDDL1(cur)
676 for sql in self._populate():
677 cur.execute(sql)
678
679 cur.execute('select name from %sbooze' % self.table_prefix)
680 rows1 = cur.fetchone()
681 rows23 = cur.fetchmany(2)
682 rows4 = cur.fetchone()
683 rows56 = cur.fetchall()
684 self.failUnless(cur.rowcount in (-1,6))
685 self.assertEqual(len(rows23),2,
686 'fetchmany returned incorrect number of rows'
687 )
688 self.assertEqual(len(rows56),2,
689 'fetchall returned incorrect number of rows'
690 )
691
692 rows = [rows1[0]]
693 rows.extend([rows23[0][0],rows23[1][0]])
694 rows.append(rows4[0])
695 rows.extend([rows56[0][0],rows56[1][0]])
696 rows.sort()
697 for i in range(0,len(self.samples)):
698 self.assertEqual(rows[i],self.samples[i],
699 'incorrect data retrieved or inserted'
700 )
701 finally:
702 con.close()
703
704 def help_nextset_setUp(self,cur):
705 ''' Should create a procedure called deleteme
706 that returns two result sets, first the
707 number of rows in booze then "name from booze"
708 '''
709 raise NotImplementedError,'Helper not implemented'
710 #sql="""
711 # create procedure deleteme as
712 # begin
713 # select count(*) from booze
714 # select name from booze
715 # end
716 #"""
717 #cur.execute(sql)
718
719 def help_nextset_tearDown(self,cur):
720 'If cleaning up is needed after nextSetTest'
721 raise NotImplementedError,'Helper not implemented'
722 #cur.execute("drop procedure deleteme")
723
724 def test_nextset(self):
725 con = self._connect()
726 try:
727 cur = con.cursor()
728 if not hasattr(cur,'nextset'):
729 return
730
731 try:
732 self.executeDDL1(cur)
733 sql=self._populate()
734 for sql in self._populate():
735 cur.execute(sql)
736
737 self.help_nextset_setUp(cur)
738
739 cur.callproc('deleteme')
740 numberofrows=cur.fetchone()
741 assert numberofrows[0]== len(self.samples)
742 assert cur.nextset()
743 names=cur.fetchall()
744 assert len(names) == len(self.samples)
745 s=cur.nextset()
746 assert s == None,'No more return sets, should return None'
747 finally:
748 self.help_nextset_tearDown(cur)
749
750 finally:
751 con.close()
752
753 def test_nextset(self):
754 raise NotImplementedError,'Drivers need to override this test'
755
756 def test_arraysize(self):
757 # Not much here - rest of the tests for this are in test_fetchmany
758 con = self._connect()
759 try:
760 cur = con.cursor()
761 self.failUnless(hasattr(cur,'arraysize'),
762 'cursor.arraysize must be defined'
763 )
764 finally:
765 con.close()
766
767 def test_setinputsizes(self):
768 con = self._connect()
769 try:
770 cur = con.cursor()
771 cur.setinputsizes( (25,) )
772 self._paraminsert(cur) # Make sure cursor still works
773 finally:
774 con.close()
775
776 def test_setoutputsize_basic(self):
777 # Basic test is to make sure setoutputsize doesn't blow up
778 con = self._connect()
779 try:
780 cur = con.cursor()
781 cur.setoutputsize(1000)
782 cur.setoutputsize(2000,0)
783 self._paraminsert(cur) # Make sure the cursor still works
784 finally:
785 con.close()
786
787 def test_setoutputsize(self):
788 # Real test for setoutputsize is driver dependant
789 raise NotImplementedError,'Driver need to override this test'
790
791 def test_None(self):
792 con = self._connect()
793 try:
794 cur = con.cursor()
795 self.executeDDL1(cur)
796 cur.execute('insert into %sbooze values (NULL)' % self.table_prefix)
797 cur.execute('select name from %sbooze' % self.table_prefix)
798 r = cur.fetchall()
799 self.assertEqual(len(r),1)
800 self.assertEqual(len(r[0]),1)
801 self.assertEqual(r[0][0],None,'NULL value not returned as None')
802 finally:
803 con.close()
804
805 def test_Date(self):
806 d1 = self.driver.Date(2002,12,25)
807 d2 = self.driver.DateFromTicks(time.mktime((2002,12,25,0,0,0,0,0,0)))
808 # Can we assume this? API doesn't specify, but it seems implied
809 # self.assertEqual(str(d1),str(d2))
810
811 def test_Time(self):
812 t1 = self.driver.Time(13,45,30)
813 t2 = self.driver.TimeFromTicks(time.mktime((2001,1,1,13,45,30,0,0,0)))
814 # Can we assume this? API doesn't specify, but it seems implied
815 # self.assertEqual(str(t1),str(t2))
816
817 def test_Timestamp(self):
818 t1 = self.driver.Timestamp(2002,12,25,13,45,30)
819 t2 = self.driver.TimestampFromTicks(
820 time.mktime((2002,12,25,13,45,30,0,0,0))
821 )
822 # Can we assume this? API doesn't specify, but it seems implied
823 # self.assertEqual(str(t1),str(t2))
824
825 def test_Binary(self):
826 b = self.driver.Binary('Something')
827 b = self.driver.Binary('')
828
829 def test_STRING(self):
830 self.failUnless(hasattr(self.driver,'STRING'),
831 'module.STRING must be defined'
832 )
833
834 def test_BINARY(self):
835 self.failUnless(hasattr(self.driver,'BINARY'),
836 'module.BINARY must be defined.'
837 )
838
839 def test_NUMBER(self):
840 self.failUnless(hasattr(self.driver,'NUMBER'),
841 'module.NUMBER must be defined.'
842 )
843
844 def test_DATETIME(self):
845 self.failUnless(hasattr(self.driver,'DATETIME'),
846 'module.DATETIME must be defined.'
847 )
848
849 def test_ROWID(self):
850 self.failUnless(hasattr(self.driver,'ROWID'),
851 'module.ROWID must be defined.'
852 )
853