Skip to content

Commit 36607ac

Browse files
committed
refactor! move regression tests in their own class to easily extend them
1 parent e78dc57 commit 36607ac

1 file changed

Lines changed: 92 additions & 124 deletions

File tree

Lib/test/test_sqlite3/test_dbapi.py

Lines changed: 92 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -728,21 +728,6 @@ def test_database_keyword(self):
728728
self.assertEqual(type(cx), sqlite.Connection)
729729

730730

731-
class ParamsCxCloseInIterMany:
732-
def __init__(self, cx):
733-
self.cx = cx
734-
735-
def __iter__(self):
736-
self.cx.close()
737-
return iter([(1,), (2,), (3,)])
738-
739-
740-
def ParamsCxCloseInNext(cx):
741-
for i in range(10):
742-
cx.close()
743-
yield (i,)
744-
745-
746731
class CursorTests(unittest.TestCase):
747732
def setUp(self):
748733
self.cx = sqlite.connect(":memory:")
@@ -874,31 +859,6 @@ def __getitem__(slf, x):
874859
with self.assertRaises(ZeroDivisionError):
875860
self.cu.execute("select name from test where name=?", L())
876861

877-
def test_execute_and_concurrent_close_in___getitem__(self):
878-
# Prevent SIGSEGV when closing the connection while binding parameters.
879-
#
880-
# Internally, the connection's state is checked after bind_parameters().
881-
# Without this check, we would only be aware of the closed connection
882-
# by calling an sqlite3 function afterwards. However, it is important
883-
# that we report the error before leaving the execute() call.
884-
#
885-
# Regression test for https://github.com/python/cpython/issues/143198.
886-
887-
class PT:
888-
def __getitem__(self, i):
889-
cx.close()
890-
return 1
891-
def __len__(self):
892-
return 1
893-
894-
cx = sqlite.connect(":memory:")
895-
cx.execute("create table tmp(a number)")
896-
self.addCleanup(cx.close)
897-
cu = cx.cursor()
898-
msg = r"Cannot operate on a closed database\."
899-
with self.assertRaisesRegex(sqlite.ProgrammingError, msg):
900-
cu.execute("insert into tmp(a) values (?)", PT())
901-
902862
def test_execute_named_param_and_sequence(self):
903863
dataset = (
904864
("select :a", (1,)),
@@ -1070,56 +1030,6 @@ def test_execute_many_not_iterable(self):
10701030
with self.assertRaises(TypeError):
10711031
self.cu.executemany("insert into test(income) values (?)", 42)
10721032

1073-
@subTests("params_factory", (ParamsCxCloseInIterMany, ParamsCxCloseInNext))
1074-
def test_executemany_and_concurrent_close_in___iter__(self, params_factory):
1075-
# Prevent SIGSEGV with iterable of parameters closing the connection.
1076-
# Regression test for https://github.com/python/cpython/issues/143198.
1077-
cx = sqlite.connect(":memory:")
1078-
cx.execute("create table tmp(a number)")
1079-
self.addCleanup(cx.close)
1080-
cu = cx.cursor()
1081-
msg = r"Cannot operate on a closed database\."
1082-
with self.assertRaisesRegex(sqlite.ProgrammingError, msg):
1083-
cu.executemany("insert into tmp(a) values (?)", params_factory(cx))
1084-
1085-
# The test constructs an iterable of parameters of length 'n'
1086-
# and the connection is closed when we access the j-th one.
1087-
# The iterable is of type 'map' but the test wraps that map
1088-
# with 'iterable_wrapper' to exercise internals.
1089-
@subTests(("j", "n"), ([0, 1], [0, 3], [1, 3], [2, 3]))
1090-
@subTests("iterable_wrapper", (list, lambda x: x, lambda x: iter(x)))
1091-
def test_executemany_and_concurrent_close_in___getitem__(
1092-
self, j, n, iterable_wrapper
1093-
):
1094-
# Prevent SIGSEGV when closing the connection while binding parameters.
1095-
#
1096-
# Internally, the connection's state is checked after bind_parameters().
1097-
# Without this check, we would only be aware of the closed connection
1098-
# by calling an sqlite3 function afterwards. However, it is important
1099-
# that we report the error before leaving executemany() call.
1100-
#
1101-
# Regression test for https://github.com/python/cpython/issues/143198.
1102-
1103-
cx = sqlite.connect(":memory:")
1104-
cx.execute("create table tmp(a number)")
1105-
self.addCleanup(cx.close)
1106-
1107-
class PT:
1108-
def __init__(self, value):
1109-
self.value = value
1110-
def __getitem__(self, i):
1111-
if self.value == j:
1112-
cx.close()
1113-
return self.value
1114-
def __len__(self):
1115-
return 1
1116-
1117-
cu = cx.cursor()
1118-
msg = r"Cannot operate on a closed database\."
1119-
items = iterable_wrapper(map(PT, range(n)))
1120-
with self.assertRaisesRegex(sqlite.ProgrammingError, msg):
1121-
cu.executemany("insert into tmp(a) values (?)", items)
1122-
11231033
def test_fetch_iter(self):
11241034
# Optional DB-API extension.
11251035
self.cu.execute("delete from test")
@@ -1801,12 +1711,62 @@ def test_connection_execute(self):
18011711
result = self.con.execute("select 5").fetchone()[0]
18021712
self.assertEqual(result, 5, "Basic test of Connection.execute")
18031713

1804-
def test_connection_execute_close_in___getitem__(self):
1805-
# See CursorTests.test_execute_and_concurrent_close_in___getitem__().
1714+
def test_connection_executemany(self):
1715+
con = self.con
1716+
con.execute("create table test(foo)")
1717+
con.executemany("insert into test(foo) values (?)", [(3,), (4,)])
1718+
result = con.execute("select foo from test order by foo").fetchall()
1719+
self.assertEqual(result[0][0], 3, "Basic test of Connection.executemany")
1720+
self.assertEqual(result[1][0], 4, "Basic test of Connection.executemany")
1721+
1722+
def test_connection_executescript(self):
1723+
con = self.con
1724+
con.executescript("""
1725+
CREATE TABLE test(foo);
1726+
INSERT INTO test(foo) VALUES (5);
1727+
""")
1728+
result = con.execute("select foo from test").fetchone()[0]
1729+
self.assertEqual(result, 5, "Basic test of Connection.executescript")
1730+
1731+
1732+
class ParamsCxCloseInIterMany:
1733+
def __init__(self, cx):
1734+
self.cx = cx
1735+
1736+
def __iter__(self):
1737+
self.cx.close()
1738+
return iter([(1,), (2,), (3,)])
1739+
18061740

1741+
def ParamsCxCloseInNext(cx):
1742+
for i in range(10):
1743+
cx.close()
1744+
yield (i,)
1745+
1746+
1747+
class ExecutionConcurrentlyCloseConnectionBaseTests:
1748+
"""Tests when execute() and executemany() concurrently close the connection."""
1749+
1750+
def inittest(self):
1751+
"""Return a pair (connection, connection or cursor) to use in tests."""
18071752
cx = sqlite.connect(":memory:")
18081753
cx.execute("create table tmp(a number)")
18091754
self.addCleanup(cx.close)
1755+
return cx, self.interface(cx)
1756+
1757+
def interface(self, connection):
1758+
"""Return a cursor-like interface from a given SQLite3 connection."""
1759+
raise NotImplementedError
1760+
1761+
def test_execute_use___getitem__(self):
1762+
# Prevent SIGSEGV when closing the connection while binding parameters.
1763+
#
1764+
# Internally, the connection's state is checked after bind_parameters().
1765+
# Without this check, we would only be aware of the closed connection
1766+
# by calling an sqlite3 function afterwards. However, it is important
1767+
# that we report the error before leaving the execute() call.
1768+
#
1769+
# Regression test for https://github.com/python/cpython/issues/143198.
18101770

18111771
class PT:
18121772
def __getitem__(self, i):
@@ -1815,39 +1775,37 @@ def __getitem__(self, i):
18151775
def __len__(self):
18161776
return 1
18171777

1778+
cx, cu = self.inittest()
18181779
msg = r"Cannot operate on a closed database\."
18191780
with self.assertRaisesRegex(sqlite.ProgrammingError, msg):
1820-
cx.execute("insert into tmp(a) values (?)", PT())
1821-
1822-
def test_connection_executemany(self):
1823-
con = self.con
1824-
con.execute("create table test(foo)")
1825-
con.executemany("insert into test(foo) values (?)", [(3,), (4,)])
1826-
result = con.execute("select foo from test order by foo").fetchall()
1827-
self.assertEqual(result[0][0], 3, "Basic test of Connection.executemany")
1828-
self.assertEqual(result[1][0], 4, "Basic test of Connection.executemany")
1781+
cu.execute("insert into tmp(a) values (?)", PT())
18291782

18301783
@subTests("params_factory", (ParamsCxCloseInIterMany, ParamsCxCloseInNext))
1831-
def test_connection_executemany_close_in___iter__(self, params_factory):
1784+
def test_executemany_use___iter__(self, params_factory):
18321785
# Prevent SIGSEGV with iterable of parameters closing the connection.
18331786
# Regression test for https://github.com/python/cpython/issues/143198.
1834-
cx = sqlite.connect(":memory:")
1835-
cx.execute("create table tmp(a number)")
1836-
self.addCleanup(cx.close)
1787+
cx, cu = self.inittest()
18371788
msg = r"Cannot operate on a closed database\."
18381789
with self.assertRaisesRegex(sqlite.ProgrammingError, msg):
1839-
cx.executemany("insert into tmp(a) values (?)", params_factory(cx))
1790+
cu.executemany("insert into tmp(a) values (?)", params_factory(cx))
18401791

1792+
# The test constructs an iterable of parameters of length 'n'
1793+
# and the connection is closed when we access the j-th one.
1794+
# The iterable is of type 'map' but the test wraps that map
1795+
# with 'iterable_wrapper' to exercise internals.
18411796
@subTests(("j", "n"), ([0, 1], [0, 3], [1, 3], [2, 3]))
1842-
@subTests("iterable_wrapper", (list, lambda x: x))
1843-
def test_connection_executemany_close_in___getitem__(
1844-
self, j, n, iterable_wrapper,
1845-
):
1846-
# See CursorTests.test_executemany_and_concurrent_close_in___getitem__().
1797+
@subTests("iterable_wrapper", (list, lambda x: x, lambda x: iter(x)))
1798+
def test_executemany_use___getitem__(self, j, n, iterable_wrapper):
1799+
# Prevent SIGSEGV when closing the connection while binding parameters.
1800+
#
1801+
# Internally, the connection's state is checked after bind_parameters().
1802+
# Without this check, we would only be aware of the closed connection
1803+
# by calling an sqlite3 function afterwards. However, it is important
1804+
# that we report the error before leaving executemany() call.
1805+
#
1806+
# Regression test for https://github.com/python/cpython/issues/143198.
18471807

1848-
cx = sqlite.connect(":memory:")
1849-
cx.execute("create table tmp(a number)")
1850-
self.addCleanup(cx.close)
1808+
cx, cu = self.inittest()
18511809

18521810
class PT:
18531811
def __init__(self, value):
@@ -1859,19 +1817,29 @@ def __getitem__(self, i):
18591817
def __len__(self):
18601818
return 1
18611819

1862-
items = iterable_wrapper(map(PT, range(n)))
18631820
msg = r"Cannot operate on a closed database\."
1821+
items = iterable_wrapper(map(PT, range(n)))
18641822
with self.assertRaisesRegex(sqlite.ProgrammingError, msg):
1865-
cx.executemany("insert into tmp(a) values (?)", items)
1823+
cu.executemany("insert into tmp(a) values (?)", items)
1824+
1825+
1826+
class ConnectionExecutionConcurrentlyCloseConnectionTests(
1827+
ExecutionConcurrentlyCloseConnectionBaseTests,
1828+
unittest.TestCase,
1829+
):
1830+
"""Regression tests for conn.execute() and conn.executemany()."""
1831+
def interface(self, connection):
1832+
return connection
1833+
1834+
1835+
class CursorExecutionConcurrentlyCloseConnectionTests(
1836+
ExecutionConcurrentlyCloseConnectionBaseTests,
1837+
unittest.TestCase,
1838+
):
1839+
"""Regression tests for cursor.execute() and cursor.executemany()."""
1840+
def interface(self, connection):
1841+
return connection.cursor()
18661842

1867-
def test_connection_executescript(self):
1868-
con = self.con
1869-
con.executescript("""
1870-
CREATE TABLE test(foo);
1871-
INSERT INTO test(foo) VALUES (5);
1872-
""")
1873-
result = con.execute("select foo from test").fetchone()[0]
1874-
self.assertEqual(result, 5, "Basic test of Connection.executescript")
18751843

18761844

18771845
class ClosedConTests(unittest.TestCase):

0 commit comments

Comments
 (0)