blob: 12c9fb460fd780fa8501de791e38fb53069c17c8 [file] [log] [blame]
Petri Lehtinenf8547992012-02-02 17:17:36 +02001#-*- coding: iso-8859-1 -*-
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002# pysqlite2/test/dbapi.py: tests for DB-API compliance
3#
Gerhard Häringf9cee222010-03-05 15:20:03 +00004# Copyright (C) 2004-2010 Gerhard Häring <gh@ghaering.de>
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00005#
6# This file is part of pysqlite.
7#
8# This software is provided 'as-is', without any express or implied
9# warranty. In no event will the authors be held liable for any damages
10# arising from the use of this software.
11#
12# Permission is granted to anyone to use this software for any purpose,
13# including commercial applications, and to alter it and redistribute it
14# freely, subject to the following restrictions:
15#
16# 1. The origin of this software must not be misrepresented; you must not
17# claim that you wrote the original software. If you use this software
18# in a product, an acknowledgment in the product documentation would be
19# appreciated but is not required.
20# 2. Altered source versions must be plainly marked as such, and must not be
21# misrepresented as being the original software.
22# 3. This notice may not be removed or altered from any source distribution.
23
Antoine Pitroua6a4dc82017-09-07 18:56:24 +020024import threading
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000025import unittest
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000026import sqlite3 as sqlite
27
Antoine Pitrou902fc8b2013-02-10 00:02:44 +010028from test.support import TESTFN, unlink
29
30
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000031class ModuleTests(unittest.TestCase):
32 def CheckAPILevel(self):
33 self.assertEqual(sqlite.apilevel, "2.0",
34 "apilevel is %s, should be 2.0" % sqlite.apilevel)
35
36 def CheckThreadSafety(self):
37 self.assertEqual(sqlite.threadsafety, 1,
38 "threadsafety is %d, should be 1" % sqlite.threadsafety)
39
40 def CheckParamStyle(self):
41 self.assertEqual(sqlite.paramstyle, "qmark",
42 "paramstyle is '%s', should be 'qmark'" %
43 sqlite.paramstyle)
44
45 def CheckWarning(self):
Ezio Melottib3aedd42010-11-20 19:04:17 +000046 self.assertTrue(issubclass(sqlite.Warning, Exception),
Guido van Rossumcd16bf62007-06-13 18:07:49 +000047 "Warning is not a subclass of Exception")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000048
49 def CheckError(self):
Gregory P. Smith04cecaf2009-07-04 08:32:15 +000050 self.assertTrue(issubclass(sqlite.Error, Exception),
Guido van Rossumcd16bf62007-06-13 18:07:49 +000051 "Error is not a subclass of Exception")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000052
53 def CheckInterfaceError(self):
Gregory P. Smith04cecaf2009-07-04 08:32:15 +000054 self.assertTrue(issubclass(sqlite.InterfaceError, sqlite.Error),
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000055 "InterfaceError is not a subclass of Error")
56
57 def CheckDatabaseError(self):
Gregory P. Smith04cecaf2009-07-04 08:32:15 +000058 self.assertTrue(issubclass(sqlite.DatabaseError, sqlite.Error),
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000059 "DatabaseError is not a subclass of Error")
60
61 def CheckDataError(self):
Gregory P. Smith04cecaf2009-07-04 08:32:15 +000062 self.assertTrue(issubclass(sqlite.DataError, sqlite.DatabaseError),
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000063 "DataError is not a subclass of DatabaseError")
64
65 def CheckOperationalError(self):
Gregory P. Smith04cecaf2009-07-04 08:32:15 +000066 self.assertTrue(issubclass(sqlite.OperationalError, sqlite.DatabaseError),
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000067 "OperationalError is not a subclass of DatabaseError")
68
69 def CheckIntegrityError(self):
Gregory P. Smith04cecaf2009-07-04 08:32:15 +000070 self.assertTrue(issubclass(sqlite.IntegrityError, sqlite.DatabaseError),
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000071 "IntegrityError is not a subclass of DatabaseError")
72
73 def CheckInternalError(self):
Gregory P. Smith04cecaf2009-07-04 08:32:15 +000074 self.assertTrue(issubclass(sqlite.InternalError, sqlite.DatabaseError),
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000075 "InternalError is not a subclass of DatabaseError")
76
77 def CheckProgrammingError(self):
Gregory P. Smith04cecaf2009-07-04 08:32:15 +000078 self.assertTrue(issubclass(sqlite.ProgrammingError, sqlite.DatabaseError),
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000079 "ProgrammingError is not a subclass of DatabaseError")
80
81 def CheckNotSupportedError(self):
Gregory P. Smith04cecaf2009-07-04 08:32:15 +000082 self.assertTrue(issubclass(sqlite.NotSupportedError,
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000083 sqlite.DatabaseError),
84 "NotSupportedError is not a subclass of DatabaseError")
85
86class ConnectionTests(unittest.TestCase):
R. David Murrayd35251d2010-06-01 01:32:12 +000087
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000088 def setUp(self):
89 self.cx = sqlite.connect(":memory:")
90 cu = self.cx.cursor()
91 cu.execute("create table test(id integer primary key, name text)")
92 cu.execute("insert into test(name) values (?)", ("foo",))
93
94 def tearDown(self):
95 self.cx.close()
96
97 def CheckCommit(self):
98 self.cx.commit()
99
100 def CheckCommitAfterNoChanges(self):
101 """
102 A commit should also work when no changes were made to the database.
103 """
104 self.cx.commit()
105 self.cx.commit()
106
107 def CheckRollback(self):
108 self.cx.rollback()
109
110 def CheckRollbackAfterNoChanges(self):
111 """
112 A rollback should also work when no changes were made to the database.
113 """
114 self.cx.rollback()
115 self.cx.rollback()
116
117 def CheckCursor(self):
118 cu = self.cx.cursor()
119
120 def CheckFailedOpen(self):
121 YOU_CANNOT_OPEN_THIS = "/foo/bar/bla/23534/mydb.db"
Berker Peksag1003b342016-06-12 22:34:49 +0300122 with self.assertRaises(sqlite.OperationalError):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000123 con = sqlite.connect(YOU_CANNOT_OPEN_THIS)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000124
125 def CheckClose(self):
126 self.cx.close()
127
128 def CheckExceptions(self):
129 # Optional DB-API extension.
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000130 self.assertEqual(self.cx.Warning, sqlite.Warning)
131 self.assertEqual(self.cx.Error, sqlite.Error)
132 self.assertEqual(self.cx.InterfaceError, sqlite.InterfaceError)
133 self.assertEqual(self.cx.DatabaseError, sqlite.DatabaseError)
134 self.assertEqual(self.cx.DataError, sqlite.DataError)
135 self.assertEqual(self.cx.OperationalError, sqlite.OperationalError)
136 self.assertEqual(self.cx.IntegrityError, sqlite.IntegrityError)
137 self.assertEqual(self.cx.InternalError, sqlite.InternalError)
138 self.assertEqual(self.cx.ProgrammingError, sqlite.ProgrammingError)
139 self.assertEqual(self.cx.NotSupportedError, sqlite.NotSupportedError)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000140
R. David Murrayd35251d2010-06-01 01:32:12 +0000141 def CheckInTransaction(self):
142 # Can't use db from setUp because we want to test initial state.
143 cx = sqlite.connect(":memory:")
144 cu = cx.cursor()
145 self.assertEqual(cx.in_transaction, False)
146 cu.execute("create table transactiontest(id integer primary key, name text)")
147 self.assertEqual(cx.in_transaction, False)
148 cu.execute("insert into transactiontest(name) values (?)", ("foo",))
149 self.assertEqual(cx.in_transaction, True)
150 cu.execute("select name from transactiontest where name=?", ["foo"])
151 row = cu.fetchone()
152 self.assertEqual(cx.in_transaction, True)
153 cx.commit()
154 self.assertEqual(cx.in_transaction, False)
155 cu.execute("select name from transactiontest where name=?", ["foo"])
156 row = cu.fetchone()
157 self.assertEqual(cx.in_transaction, False)
158
159 def CheckInTransactionRO(self):
160 with self.assertRaises(AttributeError):
161 self.cx.in_transaction = True
162
Antoine Pitrou902fc8b2013-02-10 00:02:44 +0100163 def CheckOpenUri(self):
164 if sqlite.sqlite_version_info < (3, 7, 7):
165 with self.assertRaises(sqlite.NotSupportedError):
166 sqlite.connect(':memory:', uri=True)
167 return
168 self.addCleanup(unlink, TESTFN)
169 with sqlite.connect(TESTFN) as cx:
170 cx.execute('create table test(id integer)')
171 with sqlite.connect('file:' + TESTFN, uri=True) as cx:
172 cx.execute('insert into test(id) values(0)')
173 with sqlite.connect('file:' + TESTFN + '?mode=ro', uri=True) as cx:
174 with self.assertRaises(sqlite.OperationalError):
175 cx.execute('insert into test(id) values(1)')
176
Berker Peksagf85bce72016-06-14 14:19:02 +0300177 @unittest.skipIf(sqlite.sqlite_version_info >= (3, 3, 1),
178 'needs sqlite versions older than 3.3.1')
Berker Peksag7bea2342016-06-12 14:09:51 +0300179 def CheckSameThreadErrorOnOldVersion(self):
Berker Peksag7bea2342016-06-12 14:09:51 +0300180 with self.assertRaises(sqlite.NotSupportedError) as cm:
181 sqlite.connect(':memory:', check_same_thread=False)
182 self.assertEqual(str(cm.exception), 'shared connections not available')
Antoine Pitrou902fc8b2013-02-10 00:02:44 +0100183
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000184class CursorTests(unittest.TestCase):
185 def setUp(self):
186 self.cx = sqlite.connect(":memory:")
187 self.cu = self.cx.cursor()
Berker Peksage0b70cd2016-06-14 15:25:36 +0300188 self.cu.execute(
189 "create table test(id integer primary key, name text, "
190 "income number, unique_test text unique)"
191 )
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000192 self.cu.execute("insert into test(name) values (?)", ("foo",))
193
194 def tearDown(self):
195 self.cu.close()
196 self.cx.close()
197
198 def CheckExecuteNoArgs(self):
199 self.cu.execute("delete from test")
200
201 def CheckExecuteIllegalSql(self):
Berker Peksag1003b342016-06-12 22:34:49 +0300202 with self.assertRaises(sqlite.OperationalError):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000203 self.cu.execute("select asdf")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000204
205 def CheckExecuteTooMuchSql(self):
Berker Peksag1003b342016-06-12 22:34:49 +0300206 with self.assertRaises(sqlite.Warning):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000207 self.cu.execute("select 5+4; select 4+5")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000208
209 def CheckExecuteTooMuchSql2(self):
210 self.cu.execute("select 5+4; -- foo bar")
211
212 def CheckExecuteTooMuchSql3(self):
213 self.cu.execute("""
214 select 5+4;
215
216 /*
217 foo
218 */
219 """)
220
221 def CheckExecuteWrongSqlArg(self):
Berker Peksag1003b342016-06-12 22:34:49 +0300222 with self.assertRaises(ValueError):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000223 self.cu.execute(42)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000224
225 def CheckExecuteArgInt(self):
226 self.cu.execute("insert into test(id) values (?)", (42,))
227
228 def CheckExecuteArgFloat(self):
229 self.cu.execute("insert into test(income) values (?)", (2500.32,))
230
231 def CheckExecuteArgString(self):
232 self.cu.execute("insert into test(name) values (?)", ("Hugo",))
233
Petri Lehtinen023fe332012-02-01 22:18:19 +0200234 def CheckExecuteArgStringWithZeroByte(self):
235 self.cu.execute("insert into test(name) values (?)", ("Hu\x00go",))
236
237 self.cu.execute("select name from test where id=?", (self.cu.lastrowid,))
238 row = self.cu.fetchone()
239 self.assertEqual(row[0], "Hu\x00go")
240
Berker Peksagc4154402016-06-12 13:41:47 +0300241 def CheckExecuteNonIterable(self):
242 with self.assertRaises(ValueError) as cm:
243 self.cu.execute("insert into test(id) values (?)", 42)
244 self.assertEqual(str(cm.exception), 'parameters are of unsupported type')
245
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000246 def CheckExecuteWrongNoOfArgs1(self):
247 # too many parameters
Berker Peksag1003b342016-06-12 22:34:49 +0300248 with self.assertRaises(sqlite.ProgrammingError):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000249 self.cu.execute("insert into test(id) values (?)", (17, "Egon"))
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000250
251 def CheckExecuteWrongNoOfArgs2(self):
252 # too little parameters
Berker Peksag1003b342016-06-12 22:34:49 +0300253 with self.assertRaises(sqlite.ProgrammingError):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000254 self.cu.execute("insert into test(id) values (?)")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000255
256 def CheckExecuteWrongNoOfArgs3(self):
257 # no parameters, parameters are needed
Berker Peksag1003b342016-06-12 22:34:49 +0300258 with self.assertRaises(sqlite.ProgrammingError):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000259 self.cu.execute("insert into test(id) values (?)")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000260
Gerhard Häringe7ea7452008-03-29 00:45:29 +0000261 def CheckExecuteParamList(self):
262 self.cu.execute("insert into test(name) values ('foo')")
263 self.cu.execute("select name from test where name=?", ["foo"])
264 row = self.cu.fetchone()
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000265 self.assertEqual(row[0], "foo")
Gerhard Häringe7ea7452008-03-29 00:45:29 +0000266
267 def CheckExecuteParamSequence(self):
268 class L(object):
269 def __len__(self):
270 return 1
271 def __getitem__(self, x):
272 assert x == 0
273 return "foo"
274
275 self.cu.execute("insert into test(name) values ('foo')")
276 self.cu.execute("select name from test where name=?", L())
277 row = self.cu.fetchone()
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000278 self.assertEqual(row[0], "foo")
Gerhard Häringe7ea7452008-03-29 00:45:29 +0000279
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000280 def CheckExecuteDictMapping(self):
281 self.cu.execute("insert into test(name) values ('foo')")
282 self.cu.execute("select name from test where name=:name", {"name": "foo"})
283 row = self.cu.fetchone()
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000284 self.assertEqual(row[0], "foo")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000285
Gerhard Häringe7ea7452008-03-29 00:45:29 +0000286 def CheckExecuteDictMapping_Mapping(self):
287 class D(dict):
288 def __missing__(self, key):
289 return "foo"
290
291 self.cu.execute("insert into test(name) values ('foo')")
292 self.cu.execute("select name from test where name=:name", D())
293 row = self.cu.fetchone()
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000294 self.assertEqual(row[0], "foo")
Gerhard Häringe7ea7452008-03-29 00:45:29 +0000295
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000296 def CheckExecuteDictMappingTooLittleArgs(self):
297 self.cu.execute("insert into test(name) values ('foo')")
Berker Peksag1003b342016-06-12 22:34:49 +0300298 with self.assertRaises(sqlite.ProgrammingError):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000299 self.cu.execute("select name from test where name=:name and id=:id", {"name": "foo"})
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000300
301 def CheckExecuteDictMappingNoArgs(self):
302 self.cu.execute("insert into test(name) values ('foo')")
Berker Peksag1003b342016-06-12 22:34:49 +0300303 with self.assertRaises(sqlite.ProgrammingError):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000304 self.cu.execute("select name from test where name=:name")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000305
306 def CheckExecuteDictMappingUnnamed(self):
307 self.cu.execute("insert into test(name) values ('foo')")
Berker Peksag1003b342016-06-12 22:34:49 +0300308 with self.assertRaises(sqlite.ProgrammingError):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000309 self.cu.execute("select name from test where name=?", {"name": "foo"})
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000310
311 def CheckClose(self):
312 self.cu.close()
313
314 def CheckRowcountExecute(self):
315 self.cu.execute("delete from test")
316 self.cu.execute("insert into test(name) values ('foo')")
317 self.cu.execute("insert into test(name) values ('foo')")
318 self.cu.execute("update test set name='bar'")
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000319 self.assertEqual(self.cu.rowcount, 2)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000320
Georg Brandlf78e02b2008-06-10 17:40:04 +0000321 def CheckRowcountSelect(self):
322 """
323 pysqlite does not know the rowcount of SELECT statements, because we
324 don't fetch all rows after executing the select statement. The rowcount
325 has thus to be -1.
326 """
327 self.cu.execute("select 5 union select 6")
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000328 self.assertEqual(self.cu.rowcount, -1)
Georg Brandlf78e02b2008-06-10 17:40:04 +0000329
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000330 def CheckRowcountExecutemany(self):
331 self.cu.execute("delete from test")
332 self.cu.executemany("insert into test(name) values (?)", [(1,), (2,), (3,)])
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000333 self.assertEqual(self.cu.rowcount, 3)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000334
335 def CheckTotalChanges(self):
336 self.cu.execute("insert into test(name) values ('foo')")
337 self.cu.execute("insert into test(name) values ('foo')")
Berker Peksag48b5c982016-06-14 00:42:50 +0300338 self.assertLess(2, self.cx.total_changes, msg='total changes reported wrong value')
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000339
340 # Checks for executemany:
341 # Sequences are required by the DB-API, iterators
342 # enhancements in pysqlite.
343
344 def CheckExecuteManySequence(self):
345 self.cu.executemany("insert into test(income) values (?)", [(x,) for x in range(100, 110)])
346
347 def CheckExecuteManyIterator(self):
348 class MyIter:
349 def __init__(self):
350 self.value = 5
351
Georg Brandla18af4e2007-04-21 15:47:16 +0000352 def __next__(self):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000353 if self.value == 10:
354 raise StopIteration
355 else:
356 self.value += 1
357 return (self.value,)
358
359 self.cu.executemany("insert into test(income) values (?)", MyIter())
360
361 def CheckExecuteManyGenerator(self):
362 def mygen():
363 for i in range(5):
364 yield (i,)
365
366 self.cu.executemany("insert into test(income) values (?)", mygen())
367
368 def CheckExecuteManyWrongSqlArg(self):
Berker Peksag1003b342016-06-12 22:34:49 +0300369 with self.assertRaises(ValueError):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000370 self.cu.executemany(42, [(3,)])
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000371
372 def CheckExecuteManySelect(self):
Berker Peksag1003b342016-06-12 22:34:49 +0300373 with self.assertRaises(sqlite.ProgrammingError):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000374 self.cu.executemany("select ?", [(3,)])
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000375
376 def CheckExecuteManyNotIterable(self):
Berker Peksag1003b342016-06-12 22:34:49 +0300377 with self.assertRaises(TypeError):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000378 self.cu.executemany("insert into test(income) values (?)", 42)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000379
380 def CheckFetchIter(self):
381 # Optional DB-API extension.
382 self.cu.execute("delete from test")
383 self.cu.execute("insert into test(id) values (?)", (5,))
384 self.cu.execute("insert into test(id) values (?)", (6,))
385 self.cu.execute("select id from test order by id")
386 lst = []
387 for row in self.cu:
388 lst.append(row[0])
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000389 self.assertEqual(lst[0], 5)
390 self.assertEqual(lst[1], 6)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000391
392 def CheckFetchone(self):
393 self.cu.execute("select name from test")
394 row = self.cu.fetchone()
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000395 self.assertEqual(row[0], "foo")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000396 row = self.cu.fetchone()
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000397 self.assertEqual(row, None)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000398
399 def CheckFetchoneNoStatement(self):
400 cur = self.cx.cursor()
401 row = cur.fetchone()
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000402 self.assertEqual(row, None)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000403
404 def CheckArraySize(self):
405 # must default ot 1
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000406 self.assertEqual(self.cu.arraysize, 1)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000407
408 # now set to 2
409 self.cu.arraysize = 2
410
411 # now make the query return 3 rows
412 self.cu.execute("delete from test")
413 self.cu.execute("insert into test(name) values ('A')")
414 self.cu.execute("insert into test(name) values ('B')")
415 self.cu.execute("insert into test(name) values ('C')")
416 self.cu.execute("select name from test")
417 res = self.cu.fetchmany()
418
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000419 self.assertEqual(len(res), 2)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000420
421 def CheckFetchmany(self):
422 self.cu.execute("select name from test")
423 res = self.cu.fetchmany(100)
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000424 self.assertEqual(len(res), 1)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000425 res = self.cu.fetchmany(100)
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000426 self.assertEqual(res, [])
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000427
Gerhard Häringe7ea7452008-03-29 00:45:29 +0000428 def CheckFetchmanyKwArg(self):
429 """Checks if fetchmany works with keyword arguments"""
430 self.cu.execute("select name from test")
431 res = self.cu.fetchmany(size=100)
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000432 self.assertEqual(len(res), 1)
Gerhard Häringe7ea7452008-03-29 00:45:29 +0000433
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000434 def CheckFetchall(self):
435 self.cu.execute("select name from test")
436 res = self.cu.fetchall()
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000437 self.assertEqual(len(res), 1)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000438 res = self.cu.fetchall()
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000439 self.assertEqual(res, [])
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000440
441 def CheckSetinputsizes(self):
442 self.cu.setinputsizes([3, 4, 5])
443
444 def CheckSetoutputsize(self):
445 self.cu.setoutputsize(5, 0)
446
447 def CheckSetoutputsizeNoColumn(self):
448 self.cu.setoutputsize(42)
449
450 def CheckCursorConnection(self):
451 # Optional DB-API extension.
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000452 self.assertEqual(self.cu.connection, self.cx)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000453
454 def CheckWrongCursorCallable(self):
Berker Peksag1003b342016-06-12 22:34:49 +0300455 with self.assertRaises(TypeError):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000456 def f(): pass
457 cur = self.cx.cursor(f)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000458
459 def CheckCursorWrongClass(self):
460 class Foo: pass
461 foo = Foo()
Berker Peksag1003b342016-06-12 22:34:49 +0300462 with self.assertRaises(TypeError):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000463 cur = sqlite.Cursor(foo)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000464
Berker Peksage0b70cd2016-06-14 15:25:36 +0300465 def CheckLastRowIDOnReplace(self):
466 """
467 INSERT OR REPLACE and REPLACE INTO should produce the same behavior.
468 """
469 sql = '{} INTO test(id, unique_test) VALUES (?, ?)'
470 for statement in ('INSERT OR REPLACE', 'REPLACE'):
471 with self.subTest(statement=statement):
472 self.cu.execute(sql.format(statement), (1, 'foo'))
473 self.assertEqual(self.cu.lastrowid, 1)
474
475 def CheckLastRowIDOnIgnore(self):
476 self.cu.execute(
477 "insert or ignore into test(unique_test) values (?)",
478 ('test',))
479 self.assertEqual(self.cu.lastrowid, 2)
480 self.cu.execute(
481 "insert or ignore into test(unique_test) values (?)",
482 ('test',))
483 self.assertEqual(self.cu.lastrowid, 2)
484
485 def CheckLastRowIDInsertOR(self):
486 results = []
487 for statement in ('FAIL', 'ABORT', 'ROLLBACK'):
488 sql = 'INSERT OR {} INTO test(unique_test) VALUES (?)'
489 with self.subTest(statement='INSERT OR {}'.format(statement)):
490 self.cu.execute(sql.format(statement), (statement,))
491 results.append((statement, self.cu.lastrowid))
492 with self.assertRaises(sqlite.IntegrityError):
493 self.cu.execute(sql.format(statement), (statement,))
494 results.append((statement, self.cu.lastrowid))
495 expected = [
496 ('FAIL', 2), ('FAIL', 2),
497 ('ABORT', 3), ('ABORT', 3),
498 ('ROLLBACK', 4), ('ROLLBACK', 4),
499 ]
500 self.assertEqual(results, expected)
501
502
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000503class ThreadTests(unittest.TestCase):
504 def setUp(self):
505 self.con = sqlite.connect(":memory:")
506 self.cur = self.con.cursor()
507 self.cur.execute("create table test(id integer primary key, name text, bin binary, ratio number, ts timestamp)")
508
509 def tearDown(self):
510 self.cur.close()
511 self.con.close()
512
513 def CheckConCursor(self):
514 def run(con, errors):
515 try:
516 cur = con.cursor()
517 errors.append("did not raise ProgrammingError")
518 return
519 except sqlite.ProgrammingError:
520 return
521 except:
522 errors.append("raised wrong exception")
523
524 errors = []
525 t = threading.Thread(target=run, kwargs={"con": self.con, "errors": errors})
526 t.start()
527 t.join()
528 if len(errors) > 0:
529 self.fail("\n".join(errors))
530
531 def CheckConCommit(self):
532 def run(con, errors):
533 try:
534 con.commit()
535 errors.append("did not raise ProgrammingError")
536 return
537 except sqlite.ProgrammingError:
538 return
539 except:
540 errors.append("raised wrong exception")
541
542 errors = []
543 t = threading.Thread(target=run, kwargs={"con": self.con, "errors": errors})
544 t.start()
545 t.join()
546 if len(errors) > 0:
547 self.fail("\n".join(errors))
548
549 def CheckConRollback(self):
550 def run(con, errors):
551 try:
552 con.rollback()
553 errors.append("did not raise ProgrammingError")
554 return
555 except sqlite.ProgrammingError:
556 return
557 except:
558 errors.append("raised wrong exception")
559
560 errors = []
561 t = threading.Thread(target=run, kwargs={"con": self.con, "errors": errors})
562 t.start()
563 t.join()
564 if len(errors) > 0:
565 self.fail("\n".join(errors))
566
567 def CheckConClose(self):
568 def run(con, errors):
569 try:
570 con.close()
571 errors.append("did not raise ProgrammingError")
572 return
573 except sqlite.ProgrammingError:
574 return
575 except:
576 errors.append("raised wrong exception")
577
578 errors = []
579 t = threading.Thread(target=run, kwargs={"con": self.con, "errors": errors})
580 t.start()
581 t.join()
582 if len(errors) > 0:
583 self.fail("\n".join(errors))
584
585 def CheckCurImplicitBegin(self):
586 def run(cur, errors):
587 try:
588 cur.execute("insert into test(name) values ('a')")
589 errors.append("did not raise ProgrammingError")
590 return
591 except sqlite.ProgrammingError:
592 return
593 except:
594 errors.append("raised wrong exception")
595
596 errors = []
597 t = threading.Thread(target=run, kwargs={"cur": self.cur, "errors": errors})
598 t.start()
599 t.join()
600 if len(errors) > 0:
601 self.fail("\n".join(errors))
602
603 def CheckCurClose(self):
604 def run(cur, errors):
605 try:
606 cur.close()
607 errors.append("did not raise ProgrammingError")
608 return
609 except sqlite.ProgrammingError:
610 return
611 except:
612 errors.append("raised wrong exception")
613
614 errors = []
615 t = threading.Thread(target=run, kwargs={"cur": self.cur, "errors": errors})
616 t.start()
617 t.join()
618 if len(errors) > 0:
619 self.fail("\n".join(errors))
620
621 def CheckCurExecute(self):
622 def run(cur, errors):
623 try:
624 cur.execute("select name from test")
625 errors.append("did not raise ProgrammingError")
626 return
627 except sqlite.ProgrammingError:
628 return
629 except:
630 errors.append("raised wrong exception")
631
632 errors = []
633 self.cur.execute("insert into test(name) values ('a')")
634 t = threading.Thread(target=run, kwargs={"cur": self.cur, "errors": errors})
635 t.start()
636 t.join()
637 if len(errors) > 0:
638 self.fail("\n".join(errors))
639
640 def CheckCurIterNext(self):
641 def run(cur, errors):
642 try:
643 row = cur.fetchone()
644 errors.append("did not raise ProgrammingError")
645 return
646 except sqlite.ProgrammingError:
647 return
648 except:
649 errors.append("raised wrong exception")
650
651 errors = []
652 self.cur.execute("insert into test(name) values ('a')")
653 self.cur.execute("select name from test")
654 t = threading.Thread(target=run, kwargs={"cur": self.cur, "errors": errors})
655 t.start()
656 t.join()
657 if len(errors) > 0:
658 self.fail("\n".join(errors))
659
660class ConstructorTests(unittest.TestCase):
661 def CheckDate(self):
662 d = sqlite.Date(2004, 10, 28)
663
664 def CheckTime(self):
665 t = sqlite.Time(12, 39, 35)
666
667 def CheckTimestamp(self):
668 ts = sqlite.Timestamp(2004, 10, 28, 12, 39, 35)
669
670 def CheckDateFromTicks(self):
671 d = sqlite.DateFromTicks(42)
672
673 def CheckTimeFromTicks(self):
674 t = sqlite.TimeFromTicks(42)
675
676 def CheckTimestampFromTicks(self):
677 ts = sqlite.TimestampFromTicks(42)
678
679 def CheckBinary(self):
Guido van Rossumbae07c92007-10-08 02:46:15 +0000680 b = sqlite.Binary(b"\0'")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000681
682class ExtensionTests(unittest.TestCase):
683 def CheckScriptStringSql(self):
684 con = sqlite.connect(":memory:")
685 cur = con.cursor()
686 cur.executescript("""
687 -- bla bla
688 /* a stupid comment */
689 create table a(i);
690 insert into a(i) values (5);
691 """)
692 cur.execute("select i from a")
693 res = cur.fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000694 self.assertEqual(res, 5)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000695
Gerhard Häringf9cee222010-03-05 15:20:03 +0000696 def CheckScriptSyntaxError(self):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000697 con = sqlite.connect(":memory:")
698 cur = con.cursor()
Berker Peksag1003b342016-06-12 22:34:49 +0300699 with self.assertRaises(sqlite.OperationalError):
Gerhard Häringf9cee222010-03-05 15:20:03 +0000700 cur.executescript("create table test(x); asdf; create table test2(x)")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000701
702 def CheckScriptErrorNormal(self):
703 con = sqlite.connect(":memory:")
704 cur = con.cursor()
Berker Peksag1003b342016-06-12 22:34:49 +0300705 with self.assertRaises(sqlite.OperationalError):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000706 cur.executescript("create table test(sadfsadfdsa); select foo from hurz;")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000707
Berker Peksagc4154402016-06-12 13:41:47 +0300708 def CheckCursorExecutescriptAsBytes(self):
709 con = sqlite.connect(":memory:")
710 cur = con.cursor()
711 with self.assertRaises(ValueError) as cm:
712 cur.executescript(b"create table test(foo); insert into test(foo) values (5);")
713 self.assertEqual(str(cm.exception), 'script argument must be unicode.')
714
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000715 def CheckConnectionExecute(self):
716 con = sqlite.connect(":memory:")
717 result = con.execute("select 5").fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000718 self.assertEqual(result, 5, "Basic test of Connection.execute")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000719
720 def CheckConnectionExecutemany(self):
721 con = sqlite.connect(":memory:")
722 con.execute("create table test(foo)")
723 con.executemany("insert into test(foo) values (?)", [(3,), (4,)])
724 result = con.execute("select foo from test order by foo").fetchall()
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000725 self.assertEqual(result[0][0], 3, "Basic test of Connection.executemany")
726 self.assertEqual(result[1][0], 4, "Basic test of Connection.executemany")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000727
728 def CheckConnectionExecutescript(self):
729 con = sqlite.connect(":memory:")
730 con.executescript("create table test(foo); insert into test(foo) values (5);")
731 result = con.execute("select foo from test").fetchone()[0]
Gregory P. Smith04cecaf2009-07-04 08:32:15 +0000732 self.assertEqual(result, 5, "Basic test of Connection.executescript")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000733
Gerhard Häringf9cee222010-03-05 15:20:03 +0000734class ClosedConTests(unittest.TestCase):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000735 def CheckClosedConCursor(self):
736 con = sqlite.connect(":memory:")
737 con.close()
Berker Peksag1003b342016-06-12 22:34:49 +0300738 with self.assertRaises(sqlite.ProgrammingError):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000739 cur = con.cursor()
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000740
741 def CheckClosedConCommit(self):
742 con = sqlite.connect(":memory:")
743 con.close()
Berker Peksag1003b342016-06-12 22:34:49 +0300744 with self.assertRaises(sqlite.ProgrammingError):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000745 con.commit()
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000746
747 def CheckClosedConRollback(self):
748 con = sqlite.connect(":memory:")
749 con.close()
Berker Peksag1003b342016-06-12 22:34:49 +0300750 with self.assertRaises(sqlite.ProgrammingError):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000751 con.rollback()
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000752
753 def CheckClosedCurExecute(self):
754 con = sqlite.connect(":memory:")
755 cur = con.cursor()
756 con.close()
Berker Peksag1003b342016-06-12 22:34:49 +0300757 with self.assertRaises(sqlite.ProgrammingError):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000758 cur.execute("select 4")
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000759
Gerhard Häringf9cee222010-03-05 15:20:03 +0000760 def CheckClosedCreateFunction(self):
761 con = sqlite.connect(":memory:")
762 con.close()
763 def f(x): return 17
Berker Peksag1003b342016-06-12 22:34:49 +0300764 with self.assertRaises(sqlite.ProgrammingError):
Gerhard Häringf9cee222010-03-05 15:20:03 +0000765 con.create_function("foo", 1, f)
Gerhard Häringf9cee222010-03-05 15:20:03 +0000766
767 def CheckClosedCreateAggregate(self):
768 con = sqlite.connect(":memory:")
769 con.close()
770 class Agg:
771 def __init__(self):
772 pass
773 def step(self, x):
774 pass
775 def finalize(self):
776 return 17
Berker Peksag1003b342016-06-12 22:34:49 +0300777 with self.assertRaises(sqlite.ProgrammingError):
Gerhard Häringf9cee222010-03-05 15:20:03 +0000778 con.create_aggregate("foo", 1, Agg)
Gerhard Häringf9cee222010-03-05 15:20:03 +0000779
780 def CheckClosedSetAuthorizer(self):
781 con = sqlite.connect(":memory:")
782 con.close()
783 def authorizer(*args):
784 return sqlite.DENY
Berker Peksag1003b342016-06-12 22:34:49 +0300785 with self.assertRaises(sqlite.ProgrammingError):
Gerhard Häringf9cee222010-03-05 15:20:03 +0000786 con.set_authorizer(authorizer)
Gerhard Häringf9cee222010-03-05 15:20:03 +0000787
788 def CheckClosedSetProgressCallback(self):
789 con = sqlite.connect(":memory:")
790 con.close()
791 def progress(): pass
Berker Peksag1003b342016-06-12 22:34:49 +0300792 with self.assertRaises(sqlite.ProgrammingError):
Gerhard Häringf9cee222010-03-05 15:20:03 +0000793 con.set_progress_handler(progress, 100)
Gerhard Häringf9cee222010-03-05 15:20:03 +0000794
795 def CheckClosedCall(self):
796 con = sqlite.connect(":memory:")
797 con.close()
Berker Peksag1003b342016-06-12 22:34:49 +0300798 with self.assertRaises(sqlite.ProgrammingError):
Gerhard Häringf9cee222010-03-05 15:20:03 +0000799 con()
Gerhard Häringf9cee222010-03-05 15:20:03 +0000800
801class ClosedCurTests(unittest.TestCase):
Gerhard Häringf9cee222010-03-05 15:20:03 +0000802 def CheckClosed(self):
803 con = sqlite.connect(":memory:")
804 cur = con.cursor()
805 cur.close()
806
807 for method_name in ("execute", "executemany", "executescript", "fetchall", "fetchmany", "fetchone"):
808 if method_name in ("execute", "executescript"):
809 params = ("select 4 union select 5",)
810 elif method_name == "executemany":
811 params = ("insert into foo(bar) values (?)", [(3,), (4,)])
812 else:
813 params = []
814
Berker Peksag1003b342016-06-12 22:34:49 +0300815 with self.assertRaises(sqlite.ProgrammingError):
Gerhard Häringf9cee222010-03-05 15:20:03 +0000816 method = getattr(cur, method_name)
Gerhard Häringf9cee222010-03-05 15:20:03 +0000817 method(*params)
Gerhard Häringf9cee222010-03-05 15:20:03 +0000818
Berker Peksag4bf580d2016-09-07 02:04:34 +0300819
820class SqliteOnConflictTests(unittest.TestCase):
821 """
822 Tests for SQLite's "insert on conflict" feature.
823
824 See https://www.sqlite.org/lang_conflict.html for details.
825 """
826
827 def setUp(self):
828 self.cx = sqlite.connect(":memory:")
829 self.cu = self.cx.cursor()
830 self.cu.execute("""
831 CREATE TABLE test(
832 id INTEGER PRIMARY KEY, name TEXT, unique_name TEXT UNIQUE
833 );
834 """)
835
836 def tearDown(self):
837 self.cu.close()
838 self.cx.close()
839
840 def CheckOnConflictRollbackWithExplicitTransaction(self):
841 self.cx.isolation_level = None # autocommit mode
842 self.cu = self.cx.cursor()
843 # Start an explicit transaction.
844 self.cu.execute("BEGIN")
845 self.cu.execute("INSERT INTO test(name) VALUES ('abort_test')")
846 self.cu.execute("INSERT OR ROLLBACK INTO test(unique_name) VALUES ('foo')")
847 with self.assertRaises(sqlite.IntegrityError):
848 self.cu.execute("INSERT OR ROLLBACK INTO test(unique_name) VALUES ('foo')")
849 # Use connection to commit.
850 self.cx.commit()
851 self.cu.execute("SELECT name, unique_name from test")
852 # Transaction should have rolled back and nothing should be in table.
853 self.assertEqual(self.cu.fetchall(), [])
854
855 def CheckOnConflictAbortRaisesWithExplicitTransactions(self):
856 # Abort cancels the current sql statement but doesn't change anything
857 # about the current transaction.
858 self.cx.isolation_level = None # autocommit mode
859 self.cu = self.cx.cursor()
860 # Start an explicit transaction.
861 self.cu.execute("BEGIN")
862 self.cu.execute("INSERT INTO test(name) VALUES ('abort_test')")
863 self.cu.execute("INSERT OR ABORT INTO test(unique_name) VALUES ('foo')")
864 with self.assertRaises(sqlite.IntegrityError):
865 self.cu.execute("INSERT OR ABORT INTO test(unique_name) VALUES ('foo')")
866 self.cx.commit()
867 self.cu.execute("SELECT name, unique_name FROM test")
868 # Expect the first two inserts to work, third to do nothing.
869 self.assertEqual(self.cu.fetchall(), [('abort_test', None), (None, 'foo',)])
870
871 def CheckOnConflictRollbackWithoutTransaction(self):
872 # Start of implicit transaction
873 self.cu.execute("INSERT INTO test(name) VALUES ('abort_test')")
874 self.cu.execute("INSERT OR ROLLBACK INTO test(unique_name) VALUES ('foo')")
875 with self.assertRaises(sqlite.IntegrityError):
876 self.cu.execute("INSERT OR ROLLBACK INTO test(unique_name) VALUES ('foo')")
877 self.cu.execute("SELECT name, unique_name FROM test")
878 # Implicit transaction is rolled back on error.
879 self.assertEqual(self.cu.fetchall(), [])
880
881 def CheckOnConflictAbortRaisesWithoutTransactions(self):
882 # Abort cancels the current sql statement but doesn't change anything
883 # about the current transaction.
884 self.cu.execute("INSERT INTO test(name) VALUES ('abort_test')")
885 self.cu.execute("INSERT OR ABORT INTO test(unique_name) VALUES ('foo')")
886 with self.assertRaises(sqlite.IntegrityError):
887 self.cu.execute("INSERT OR ABORT INTO test(unique_name) VALUES ('foo')")
888 # Make sure all other values were inserted.
889 self.cu.execute("SELECT name, unique_name FROM test")
890 self.assertEqual(self.cu.fetchall(), [('abort_test', None), (None, 'foo',)])
891
892 def CheckOnConflictFail(self):
893 self.cu.execute("INSERT OR FAIL INTO test(unique_name) VALUES ('foo')")
894 with self.assertRaises(sqlite.IntegrityError):
895 self.cu.execute("INSERT OR FAIL INTO test(unique_name) VALUES ('foo')")
896 self.assertEqual(self.cu.fetchall(), [])
897
898 def CheckOnConflictIgnore(self):
899 self.cu.execute("INSERT OR IGNORE INTO test(unique_name) VALUES ('foo')")
900 # Nothing should happen.
901 self.cu.execute("INSERT OR IGNORE INTO test(unique_name) VALUES ('foo')")
902 self.cu.execute("SELECT unique_name FROM test")
903 self.assertEqual(self.cu.fetchall(), [('foo',)])
904
905 def CheckOnConflictReplace(self):
906 self.cu.execute("INSERT OR REPLACE INTO test(name, unique_name) VALUES ('Data!', 'foo')")
907 # There shouldn't be an IntegrityError exception.
908 self.cu.execute("INSERT OR REPLACE INTO test(name, unique_name) VALUES ('Very different data!', 'foo')")
909 self.cu.execute("SELECT name, unique_name FROM test")
910 self.assertEqual(self.cu.fetchall(), [('Very different data!', 'foo')])
911
912
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000913def suite():
914 module_suite = unittest.makeSuite(ModuleTests, "Check")
915 connection_suite = unittest.makeSuite(ConnectionTests, "Check")
916 cursor_suite = unittest.makeSuite(CursorTests, "Check")
917 thread_suite = unittest.makeSuite(ThreadTests, "Check")
918 constructor_suite = unittest.makeSuite(ConstructorTests, "Check")
919 ext_suite = unittest.makeSuite(ExtensionTests, "Check")
Gerhard Häringf9cee222010-03-05 15:20:03 +0000920 closed_con_suite = unittest.makeSuite(ClosedConTests, "Check")
921 closed_cur_suite = unittest.makeSuite(ClosedCurTests, "Check")
Berker Peksag4bf580d2016-09-07 02:04:34 +0300922 on_conflict_suite = unittest.makeSuite(SqliteOnConflictTests, "Check")
923 return unittest.TestSuite((
924 module_suite, connection_suite, cursor_suite, thread_suite,
925 constructor_suite, ext_suite, closed_con_suite, closed_cur_suite,
926 on_conflict_suite,
927 ))
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000928
929def test():
930 runner = unittest.TextTestRunner()
931 runner.run(suite())
932
933if __name__ == "__main__":
934 test()