oiE\dZdddZdZddlZddlZdZGdd ejZdS) aPython DB API 2.0 driver compliance unit test suite. This software is Public Domain and may be used without restrictions. "Now we have booze and barflies entering the discussion, plus rumours of DBAs on drugs... and I won't tell you what flashes through my mind each time I read the subject line with 'Anal Compliance' in it. All around this is turning out to be a thoroughly unwholesome unit test." -- Ian Bicking z$Revision: 1.15.0 $ z'Stuart Bishop NFcbeZdZdZdZdZiZdZdezZdezZ dezZ dezZ d Z d Z d Zd Zd ZdZdZdZdZdZdZdZdZdZdZdZdZdZd ZdZdZ dZ!dZ"dZ#d Z$gd!Z%d"Z&d#Z'd$Z(d%Z)d&Z*d'Z+d(Z,d)Z-d*Z.d+Z/d,Z0d-Z1d.Z2d/Z3d0Z4d1Z5d2Z6d3Z7d4Z8d5Z9d6Z:dS)7DatabaseAPI20Testa Test a database self.driver for DB API 2.0 compatibility. This implementation tests Gadfly, but the TestCase is structured so that other self.drivers can subclass this test case to ensure compiliance with the DB-API. It is expected that this TestCase may be expanded in the future if ambiguities or edge conditions are discovered. The 'Optional Extensions' are not yet being tested. self.drivers should subclass this test, overriding setUp, tearDown, self.driver, connect_args and connect_kw_args. Class specification should be as follows: import dbapi20 class mytest(dbapi20.DatabaseAPI20Test): [...] Don't 'import DatabaseAPI20Test from dbapi20', or you will confuse the unit tester - just 'import dbapi20'. N dbapi20test_z'create table %sbooze (name varchar(20))zwxYw |dS#|wxYw#t$rYdSwxYw)zself.drivers should override this method to perform required cleanup if any is necessary, such as deleting the test database. The default drops the tables that may be created. N) _connectrxddl1xddl2r commitdriverErrorclose Exception)rconcurddls rtearDownzDatabaseAPI20Test.tearDowns  --//C jjll J 3C C((( ;,       DD sKB+$B)A&%B&A85B7A88B<B+B((B++ B98B9c |jj|ji|j}n%#t$r|dYnwxYw|S)Nz-No connect method found in self.driver module)r connect connect_argsconnect_kw_argsAttributeErrorfail)rrs rrzDatabaseAPI20Test._connectsf G# #T%6O$:NOOAA G G G IIE F F F F F GsAAcV|}|dSr )rr"rr$s r test_connectzDatabaseAPI20Test.test_connects mmoo rc |jj}||ddS#t$r|dYdSwxYw)Nz2.0zDriver doesn't define apilevel)r apilevel assertEqualr,r-)rr3s r test_apilevelzDatabaseAPI20Test.test_apilevelsd 8{+H   Xu - - - - - 8 8 8 II6 7 7 7 7 7 7 8s"&A A c |jj}||dvdS#t$r|dYdSwxYw)N)rz"Driver doesn't define threadsafety)r threadsafety assertTruer,r-)rr:s rtest_threadsafetyz#DatabaseAPI20Test.test_threadsafetyse <;3L OOLL8 9 9 9 9 9 < < < II: ; ; ; ; ; ; <#'A  A c |jj}||dvdS#t$r|dYdSwxYw)N)qmarknumericnamedformatpyformatz Driver doesn't define paramstyle)r paramstyler;r,r-)rrDs rtest_paramstylez!DatabaseAPI20Test.test_paramstyless :/J OOQQ      : : : II8 9 9 9 9 9 9 :r=c|t|jjt|t|jjt|t|jj|jj|t|jj|jj|t|jj|jj|t|jj |jj|t|jj |jj|t|jj |jj|t|jj |jjdSr ) r; issubclassr Warningr#r!InterfaceError DatabaseErrorOperationalErrorIntegrityError InternalErrorProgrammingErrorNotSupportedErrorrs rtest_Exceptionsz!DatabaseAPI20Test.test_ExceptionssT  4;#6 BBCCC  4;#4i@@AAA  4;#=t{?PQQRRR  4;#OPPQQQ  4;#?ARSSTTT  4;#=t{?PQQRRR  4;#OPPQQQ  4;#?ARSSTTT  4;#@$+BSTTUUUUUrc|}|j}||j|ju||j|ju||j|ju||j|ju||j|ju||j|ju||j |j u||j |j u||j |j udSr ) rr r;rHr!rIrJrKrLrMrNrO)rr$drvs r%test_ExceptionsAsConnectionAttributesz7DatabaseAPI20Test.test_ExceptionsAsConnectionAttributessmmook  s{2333  SY./// *c.@@AAA )S->>??? ,0DDEEE *c.@@AAA )S->>??? ,0DDEEE -1FFGGGGGrc|} ||dS#|wxYwr )rrr"r0s r test_commitzDatabaseAPI20Test.test_commitsDmmoo  JJLLL IIKKKKKCIIKKKK AAc|}t|dr- |dS#|jj$rYdSwxYwdS)Nrollback)rhasattrrXr rOr0s r test_rollbackzDatabaseAPI20Test.test_rollbacksjmmoo 3 # #   ;0      s<AAc|} |}|dS#|wxYwr )rrr"rr$r%s r test_cursorzDatabaseAPI20Test.test_cursorsDmmoo **,,C IIKKKKKCIIKKKKrVc||} |}|}|||d|jz|d|jz|}|t|d|t|dd||ddd|dS#|wxYw)N.insert into %sbooze values ('Victoria Bitter')select name from %sboozer7rVictoria Bitter rrrr table_prefixfetchallr4lenr")rr$cur1cur2boozes rtest_cursor_isolationz'DatabaseAPI20Test.test_cursor_isolations mmoo ::<Non-idempotent close is considered a bad thing by some people.) rrr" assertRaisesr r!rrTEST_FOR_NON_IDEMPOTENT_CLOSEskipTestr\s r test_closezDatabaseAPI20Test.test_closepsmmoo **,,C IIKKKKCIIKKKK $++T-=sCCC $++SZ888 )    dk/ ; ; ; ; ; MMP     s ?Ac|} |}|||dS#|wxYwr )rr _paraminsertr"r\s r test_executezDatabaseAPI20Test.test_executesXmmoo **,,C   c " " " IIKKKKKCIIKKKKs )AA+c8|||d|jz||jdv|jjdkr|d|jzdn|jjdkr|d|jzdn|jjdkr!|d |jzd d inu|jjd kr|d |jzdnF|jjdkr!|d|jzd d in|d||jdv|d|jz|}| t|dd|dd|ddg}| | |dd d| |dddd}| |dd|d|ddd|| |dd|d|ddd|dS)NzSinsert into %sbarflys values ('Victoria Bitter', 'thi%%s :may ca%%(u)se? troub:1e')rsr?zCinsert into %sbarflys values (?, 'thi%%s :may ca%%(u)se? troub:1e')Cooper'sr@zDinsert into %sbarflys values (:1, 'thi%%s :may ca%%(u)se? troub:1e')rAzGinsert into %sbarflys values (:beer, 'thi%%s :may ca%%(u)se? troub:1e')beerrrBzEinsert into %sbarflys values (%%s, 'thi%%s :may ca%%(u)se? troub:1e')rCzKinsert into %sbarflys values (%%(beer)s, 'thi%%s :may ca%%(u)se? troub:1e')zInvalid paramstylez!select name, drink from %sbarflysr8z%cursor.fetchall returned too few rowsrr7zFcursor.fetchall retrieved incorrect data, or data inserted incorrectlyrazthi%s :may ca%(u)se? troub:1ezLcursor.fetchall retrieved incorrect data, or data inserted incorrectly. Got=z , Expected=) rr rcr;rtr rDr-rdr4resort)rr%resbeerstroubles rrzDatabaseAPI20Test._paraminserts2  a  "     /000 ; !W , , KKU#$     [ #y 0 0 KKV#$     [ #w . . KKY#$$     [ #x / / KKW#$     [ #z 1 1 KK]#$$     II* + + +  /000 7$:KKLLLllnn S1&MNNNQCF1I&   !H  T    !H  T   2  F1I  D #Aq  D D8? D D    F1I  D #Aq  D D8? D D     rc|} |}||ddg}ddiddig}|jjdkr|d|jz|n|jjdkr|d |jz|n|jjd kr|d |jz|ns|jjd kr|d |jz|nD|jjdkr|d|jz|n|d||j dvd|j z| d|jz| }| t|dd|dd|ddg}|| |ddd|dz| |ddd|dS#|wxYw)Nr)Boag'srrrr?zinsert into %sbooze values (?)r@zinsert into %sbooze values (:1)rAz"insert into %sbooze values (:beer)rBz insert into %sbooze values (%%s)rCz&insert into %sbooze values (%%(beer)s)zUnknown paramstyle)rrr8zIinsert using cursor.executemany set cursor.rowcount to incorrect value %rr`r8z2cursor.fetchall retrieved incorrect number of rowsrr7zincorrect data "%s" retrievedzincorrect data retrieved)rrrr rD executemanyrcr-r;rtr rdr4rerr")rr$r%largsmargsrrs rtest_executemanyz"DatabaseAPI20Test.test_executemanysmmoo- **,,C   S ! ! !"K0Ej)FH+=>E{%004t7HH%'94458II5'72284;LLe'83369JJE':55<@QR  ./// OO '%'*|4    KK2T5FF G G G,,..C   C!Q   VAYAq *E JJLLL   a($CeAh$N      U1Xz3M N N N IIKKKKKCIIKKKKs H"II$c&|} |}||jj|j||||jj|j|d|jz| |dd| |j dv|d|jz||jj|j|d|jz|}| t|dd| |ddd | |dd | |j d v| dS#| wxYw) Nr`z?cursor.fetchone should return None if a query retrieves no rowsrqr_r7z2cursor.fetchone should have retrieved a single rowrraz(cursor.fetchone retrieved incorrect dataz > >   S ! ! !   dk/ > > > KK2T5FF G G G    Q    OOCLG3 4 4 4 KK@DDUV      dk/ > > > KK2T5FF G G G A   AO      !')S       N    OOCLG3 4 4 4 IIKKKKKCIIKKKKs GG::H)z Carlton Coldz Carlton Draftz Mountain GoatRedbackraXXXXc.fdjD}|S)zSReturn a list of sql commands to setup the DB for the fetch tests. c,g|]}djd|dS)z insert into zbooze values ('z'))rc).0srs r z/DatabaseAPI20Test._populate..Cs=   483D3D3Daaa H   r)samples)rpopulates` r _populatezDatabaseAPI20Test._populate?s4    \   rc0 |} |}||jj|jd|||D]}|||d|j z|}| t|ddd|_ |d}| t|dd|d}| t|dd|d}| t|d d | |jd vd|_ |d|j z|}| t|dd |}| t|d|}| t|d | |jd vd |_ |d|j z|}| |jd v| t|d | t|d d|D}|t!d d D]*}| |||j|d+|}| t|d d| |jd v|||d|j z|}| t|d d| |jdv|dS#|wxYw)Nr`r7zQcursor.fetchmany retrieved incorrect number of rows, default of arraysize is one. r9z3cursor.fetchmany retrieved incorrect number of rowsr8rzLcursor.fetchmany should return an empty sequence after results are exhaustedrrz0cursor.arraysize not being honoured by fetchmanyrcg|] }|d Srrrr.s rrz4DatabaseAPI20Test.test_fetchmany..'''QAaD'''rz,incorrect data retrieved by cursor.fetchmanyzfcursor.fetchmany should return an empty sequence if called after the whole result set has been fetchedselect name from %sbarflyszKcursor.fetchmany should return an empty sequence if query retrieved no rowsrq)rrr~r r! fetchmanyrrr rcr4re arraysizer;rtrrangerrr")rr$r%sqlr.rowsis rtest_fetchmanyz DatabaseAPI20Test.test_fetchmanyIsLmmooX **,,C   dk/ B B B   S ! ! !~~'' ! ! C    KK2T5FF G G G A   A/    CM a  A   AP    a  A   AP    a  A   A(    OOCLG3 4 4 4CM KK2T5FF G G G A   AM    A   SVVQ ' ' ' A   SVVQ ' ' ' OOCLG3 4 4 4CM KK2T5FF G G G==??D OOCLG3 4 4 4   SYY * * *   SYY * * *''$'''D IIKKK1a[[    GLOB ==??D   D E    OOCLG3 4 4 4   S ! ! ! KK4t7HH I I I A   A*    OOCLG3 4 4 4 IIKKKKKCIIKKKKs QQ??Rc|} |}||jj|j|||D]}||||jj|j|d|j z|}| |j dt|j fv|t|t|j dd|D}|t!dt|j D]*}||||j |d+|}|t|dd| |j dt|j fv|||d|j z|}| |j d v|t|dd |dS#|wxYw) Nr`rrz)cursor.fetchall did not retrieve all rowscg|] }|d Srrrs rrz3DatabaseAPI20Test.test_fetchall..rrrz(cursor.fetchall retrieved incorrect rowszacursor.fetchall should return an empty list if called after the whole result set has been fetchedrrqzMcursor.fetchall should return an empty list if a select query returns no rows)rrr~r r!rdrrr rcr;rtrerr4rrrr")rr$r%rrrs r test_fetchallzDatabaseAPI20Test.test_fetchallsmmoo2 **,,C   dk/ > > >   S ! ! !~~'' ! ! C       dk/ > > > KK2T5FF G G G<<>>D OOCLRT\1B1B,CC D D D   D DL!!;    ('$'''D IIKKK1c$,//00    GT\!_.X<<>>D   D >    OOCLRT\1B1B,CC D D D   S ! ! ! KK4t7HH I I I<<>>D OOCLG3 4 4 4   D 1    IIKKKKKCIIKKKKs JJ==Kc|} |}|||D]}|||d|jz|}|d}|}|}| |j dv| t|dd| t|dd|dg}| |dd|ddg||d| |dd|ddg|t!dt|jD]*} | || |j| d+ |dS#|wxYw) Nr`r8rz+fetchmany returned incorrect number of rowsz*fetchall returned incorrect number of rowsrr7z$incorrect data retrieved or inserted)rrrrr rcrrrdr;rtr4reextendappendrrrr") rr$r%rrows1rows23rows4rows56rrs rtest_mixedfetchz!DatabaseAPI20Test.test_mixedfetchsmmoo **,,C   S ! ! !~~'' ! ! C    KK2T5FF G G GLLNNE]]1%%FLLNNE\\^^F OOCLG3 4 4 4   F Q M      F Q L   !H:D KK1vay|4 5 5 5 KKa ! ! ! KK1vay|4 5 5 5 IIKKK1c$,//00    GT\!_.T  IIKKKKKCIIKKKKs H H77I c td)zShould create a procedure called deleteme that returns two result sets, first the number of rows in booze then "name from booze" Helper not implementedNotImplementedErrorrr%s rhelp_nextset_setUpz$DatabaseAPI20Test.help_nextset_setUps "":;;;rc td)z*If cleaning up is needed after nextSetTestrrrs rhelp_nextset_tearDownz'DatabaseAPI20Test.help_nextset_tearDown s!":;;;rc td)Nz"Drivers need to override this testrrs r test_nextsetzDatabaseAPI20Test.test_nextsets!"FGGGrc|} |}|t|dd|dS#|wxYw)Nrz cursor.arraysize must be defined)rrr;rYr"r\s rtest_arraysizez DatabaseAPI20Test.test_arraysizeslmmoo **,,C OO[))+M    IIKKKKKCIIKKKKs 8A$$A:c|} |}|d|||dS#|wxYw)N))rr setinputsizesrr"r\s rtest_setinputsizesz$DatabaseAPI20Test.test_setinputsizesslmmoo **,,C   e $ $ $   c " " " IIKKKKKCIIKKKKs >A**Bc2|} |}|d|dd|||dS#|wxYw)Niir)rr setoutputsizerr"r\s rtest_setoutputsize_basicz*DatabaseAPI20Test.test_setoutputsize_basic'smmoo **,,C   d # # #   dA & & &   c " " " IIKKKKKCIIKKKKs ABBc td)Nz#Driver needed to override this testrrs rtest_setoutputsizez$DatabaseAPI20Test.test_setoutputsize2s!"GHHHrcV|} |}|||d|jz|d|jz|}|t|d|t|dd||dddd|dS#|wxYw)Nz!insert into %sbooze values (NULL)r`r7rzNULL value not returned as Nonerbr{s r test_NonezDatabaseAPI20Test.test_None6smmoo **,,C   S ! ! ! KK;d>OO P P P KK2T5FF G G G A   SVVQ ' ' '   S1YY * * *   QqT!Wd,M N N N IIKKKKKCIIKKKKs C&DD(c|jddd}|jtjd}dS)N r) rrrrrrrrr)r Date DateFromTickstimemktime)rd1d2s r test_DatezDatabaseAPI20Test.test_DateDs? [  dB + + [ & &t{3S'T'T U Urc|jddd}|jtjd}dS)N -) ir7r7rrrrrr)r Time TimeFromTicksrrrt1t2s r test_TimezDatabaseAPI20Test.test_TimeJs? [  b"b ) ) [ & &t{3T'U'U V Vrc|jdddddd}|jtjd}dS)Nrrrrrr) rrrrrrrrr)r TimestampTimestampFromTicksrrrs rtest_Timestampz DatabaseAPI20Test.test_TimestampPsJ [ " "4RR < < [ + + K; < <  rcn|jd}|jd}dS)Ns Somethingr)r Binary)rbs r test_BinaryzDatabaseAPI20Test.test_BinaryXs0 K  | , , K  s # #rcX|t|jdddS)Nrnzmodule.STRING must be definedr;rYr rs r test_STRINGzDatabaseAPI20Test.test_STRING\s)  X668WXXXXXrcX|t|jdddS)NBINARYzmodule.BINARY must be defined.rrs r test_BINARYzDatabaseAPI20Test.test_BINARY_4  DK * *,L     rcX|t|jdddS)NNUMBERzmodule.NUMBER must be defined.rrs r test_NUMBERzDatabaseAPI20Test.test_NUMBERdrrcX|t|jdddS)NDATETIMEz module.DATETIME must be defined.rrs r test_DATETIMEzDatabaseAPI20Test.test_DATETIMEis4  DK , ,.P     rcX|t|jdddS)NROWIDzmodule.ROWID must be defined.rrs r test_ROWIDzDatabaseAPI20Test.test_ROWIDns)  W557VWWWWWr);__name__ __module__ __qualname____doc__r r*r+rcr rrr lowerfuncrrrr'rr1r5r<rErPrSrUrZr]rirorurzr|rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrVs5.FLO!L 4| CD IL XD < /E "\ 1EI""""""   ,888<<< : : : V V VHHH&&)))V   DJ   0E E E N///b,,,\GZZZx444lB<<<<<< HHH      III   VVV WWW    $$$YYY         XXXXXrr)r __version__ __author__runittestrTestCaserrrrrs  $BrE* 6 !&BY XY XY XY XY X)Y XY XY XY XY Xr