Skip to content

Commit 2c1ae09

Browse files
author
Erlend Egeberg Aasland
authored
bpo-43553: Improve sqlite3 test coverage (GH-26886)
1 parent 9049ea5 commit 2c1ae09

File tree

4 files changed

+100
-2
lines changed

4 files changed

+100
-2
lines changed

Lib/sqlite3/test/dbapi.py

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,8 @@
2626
import threading
2727
import unittest
2828

29-
from test.support import check_disallow_instantiation
29+
from test.support import check_disallow_instantiation, threading_helper
3030
from test.support.os_helper import TESTFN, unlink
31-
from test.support import threading_helper
3231

3332

3433
# Helper for tests using TESTFN
@@ -110,6 +109,10 @@ def test_disallow_instantiation(self):
110109
cx = sqlite.connect(":memory:")
111110
check_disallow_instantiation(self, type(cx("select 1")))
112111

112+
def test_complete_statement(self):
113+
self.assertFalse(sqlite.complete_statement("select t"))
114+
self.assertTrue(sqlite.complete_statement("create table t(t);"))
115+
113116

114117
class ConnectionTests(unittest.TestCase):
115118

@@ -225,6 +228,20 @@ def test_connection_exceptions(self):
225228
self.assertTrue(hasattr(self.cx, exc))
226229
self.assertIs(getattr(sqlite, exc), getattr(self.cx, exc))
227230

231+
def test_interrupt_on_closed_db(self):
232+
cx = sqlite.connect(":memory:")
233+
cx.close()
234+
with self.assertRaises(sqlite.ProgrammingError):
235+
cx.interrupt()
236+
237+
def test_interrupt(self):
238+
self.assertIsNone(self.cx.interrupt())
239+
240+
def test_drop_unused_refs(self):
241+
for n in range(500):
242+
cu = self.cx.execute(f"select {n}")
243+
self.assertEqual(cu.fetchone()[0], n)
244+
228245

229246
class OpenTests(unittest.TestCase):
230247
_sql = "create table test(id integer)"
@@ -594,6 +611,11 @@ def test_column_count(self):
594611
new_count = len(res.description)
595612
self.assertEqual(new_count - old_count, 1)
596613

614+
def test_same_query_in_multiple_cursors(self):
615+
cursors = [self.cx.execute("select 1") for _ in range(3)]
616+
for cu in cursors:
617+
self.assertEqual(cu.fetchall(), [(1,)])
618+
597619

598620
class ThreadTests(unittest.TestCase):
599621
def setUp(self):

Lib/sqlite3/test/factory.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ def test_sqlite_row_index(self):
123123
row[-3]
124124
with self.assertRaises(IndexError):
125125
row[2**1000]
126+
with self.assertRaises(IndexError):
127+
row[complex()] # index must be int or string
126128

127129
def test_sqlite_row_index_unicode(self):
128130
self.con.row_factory = sqlite.Row

Lib/sqlite3/test/types.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,43 @@ def test_caster_is_used(self):
381381
val = self.cur.fetchone()[0]
382382
self.assertEqual(type(val), float)
383383

384+
def test_missing_adapter(self):
385+
with self.assertRaises(sqlite.ProgrammingError):
386+
sqlite.adapt(1.) # No float adapter registered
387+
388+
def test_missing_protocol(self):
389+
with self.assertRaises(sqlite.ProgrammingError):
390+
sqlite.adapt(1, None)
391+
392+
def test_defect_proto(self):
393+
class DefectProto():
394+
def __adapt__(self):
395+
return None
396+
with self.assertRaises(sqlite.ProgrammingError):
397+
sqlite.adapt(1., DefectProto)
398+
399+
def test_defect_self_adapt(self):
400+
class DefectSelfAdapt(float):
401+
def __conform__(self, _):
402+
return None
403+
with self.assertRaises(sqlite.ProgrammingError):
404+
sqlite.adapt(DefectSelfAdapt(1.))
405+
406+
def test_custom_proto(self):
407+
class CustomProto():
408+
def __adapt__(self):
409+
return "adapted"
410+
self.assertEqual(sqlite.adapt(1., CustomProto), "adapted")
411+
412+
def test_adapt(self):
413+
val = 42
414+
self.assertEqual(float(val), sqlite.adapt(val))
415+
416+
def test_adapt_alt(self):
417+
alt = "other"
418+
self.assertEqual(alt, sqlite.adapt(1., None, alt))
419+
420+
384421
@unittest.skipUnless(zlib, "requires zlib")
385422
class BinaryConverterTests(unittest.TestCase):
386423
def convert(s):

Lib/sqlite3/test/userfunctions.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,36 @@
2121
# misrepresented as being the original software.
2222
# 3. This notice may not be removed or altered from any source distribution.
2323

24+
import contextlib
25+
import functools
26+
import io
2427
import unittest
2528
import unittest.mock
2629
import gc
2730
import sqlite3 as sqlite
2831

32+
def with_tracebacks(strings):
33+
"""Convenience decorator for testing callback tracebacks."""
34+
strings.append('Traceback')
35+
36+
def decorator(func):
37+
@functools.wraps(func)
38+
def wrapper(self, *args, **kwargs):
39+
# First, run the test with traceback enabled.
40+
sqlite.enable_callback_tracebacks(True)
41+
buf = io.StringIO()
42+
with contextlib.redirect_stderr(buf):
43+
func(self, *args, **kwargs)
44+
tb = buf.getvalue()
45+
for s in strings:
46+
self.assertIn(s, tb)
47+
48+
# Then run the test with traceback disabled.
49+
sqlite.enable_callback_tracebacks(False)
50+
func(self, *args, **kwargs)
51+
return wrapper
52+
return decorator
53+
2954
def func_returntext():
3055
return "foo"
3156
def func_returnunicode():
@@ -228,6 +253,7 @@ def test_func_return_long_long(self):
228253
val = cur.fetchone()[0]
229254
self.assertEqual(val, 1<<31)
230255

256+
@with_tracebacks(['func_raiseexception', '5/0', 'ZeroDivisionError'])
231257
def test_func_exception(self):
232258
cur = self.con.cursor()
233259
with self.assertRaises(sqlite.OperationalError) as cm:
@@ -387,20 +413,23 @@ def test_aggr_no_finalize(self):
387413
val = cur.fetchone()[0]
388414
self.assertEqual(str(cm.exception), "user-defined aggregate's 'finalize' method raised error")
389415

416+
@with_tracebacks(['__init__', '5/0', 'ZeroDivisionError'])
390417
def test_aggr_exception_in_init(self):
391418
cur = self.con.cursor()
392419
with self.assertRaises(sqlite.OperationalError) as cm:
393420
cur.execute("select excInit(t) from test")
394421
val = cur.fetchone()[0]
395422
self.assertEqual(str(cm.exception), "user-defined aggregate's '__init__' method raised error")
396423

424+
@with_tracebacks(['step', '5/0', 'ZeroDivisionError'])
397425
def test_aggr_exception_in_step(self):
398426
cur = self.con.cursor()
399427
with self.assertRaises(sqlite.OperationalError) as cm:
400428
cur.execute("select excStep(t) from test")
401429
val = cur.fetchone()[0]
402430
self.assertEqual(str(cm.exception), "user-defined aggregate's 'step' method raised error")
403431

432+
@with_tracebacks(['finalize', '5/0', 'ZeroDivisionError'])
404433
def test_aggr_exception_in_finalize(self):
405434
cur = self.con.cursor()
406435
with self.assertRaises(sqlite.OperationalError) as cm:
@@ -502,6 +531,14 @@ def authorizer_cb(action, arg1, arg2, dbname, source):
502531
raise ValueError
503532
return sqlite.SQLITE_OK
504533

534+
@with_tracebacks(['authorizer_cb', 'ValueError'])
535+
def test_table_access(self):
536+
super().test_table_access()
537+
538+
@with_tracebacks(['authorizer_cb', 'ValueError'])
539+
def test_column_access(self):
540+
super().test_table_access()
541+
505542
class AuthorizerIllegalTypeTests(AuthorizerTests):
506543
@staticmethod
507544
def authorizer_cb(action, arg1, arg2, dbname, source):

0 commit comments

Comments
 (0)