4949 u"\U00010348 " , u"Aé€\U00010348 Z" ,
5050]
5151
52+ # every connection _oracle()/_disguisedOracle() open outlives the helper call (the returned
53+ # closure keeps using it), so callers can't close it themselves - tracked here and closed once
54+ # in tearDownModule() instead of leaking to GC (ResourceWarning: unclosed database)
55+ _OPEN_CONNECTIONS = []
56+
5257
5358def _oracle (value = None , is_null = False ):
5459 con = sqlite3 .connect (":memory:" )
60+ _OPEN_CONNECTIONS .append (con )
5561 con .execute ("CREATE TABLE t (v TEXT)" )
5662 con .execute ("INSERT INTO t VALUES (?)" , (None if is_null else value ,))
5763 con .commit ()
@@ -84,6 +90,7 @@ def _disguisedOracle(blocked=None, rewrites=(), funcs=()):
8490 `funcs` registers extra SQL functions (e.g. a variadic CONCAT SQLite lacks). The
8591 engine never sees SQLite - it must adapt to whatever back-end the scenario emulates."""
8692 con = sqlite3 .connect (":memory:" )
93+ _OPEN_CONNECTIONS .append (con )
8794 for name , narg , fn in funcs :
8895 con .create_function (name , narg , fn )
8996 for stmt in _SEED :
@@ -221,6 +228,7 @@ def test_host_native_integrity_parity(self):
221228 # hostExtract must mirror the native EXACT/AMBIGUOUS verdict: in a mode with no byte-exact
222229 # witness (ordinal), both must be WHOLE_BUT_AMBIGUOUS, not native-ambiguous/host-exact.
223230 con = sqlite3 .connect (":memory:" )
231+ self .addCleanup (con .close )
224232 con .execute ("CREATE TABLE t (v TEXT)" )
225233 con .execute ("INSERT INTO t VALUES ('Admin-42')" )
226234 con .commit ()
@@ -249,6 +257,7 @@ def test_framing_length_witness_catches_capped_hex(self):
249257 # must reject the shortened token -> fall back to cell-by-cell (which reads the true
250258 # length via substring), so a 400-char value is recovered whole, not silently as 300.
251259 con = sqlite3 .connect (":memory:" )
260+ self .addCleanup (con .close )
252261 con .execute ("CREATE TABLE t (id INTEGER PRIMARY KEY, v TEXT)" )
253262 big = "A" * 400
254263 con .execute ("INSERT INTO t VALUES (1, ?)" , (big ,))
@@ -273,6 +282,7 @@ def test_integer_final_equality(self):
273282 # operands -> bisection converges off-by-one. The final `expr = recovered` check must
274283 # reject it (fail closed) rather than return a silently-wrong integer.
275284 con = sqlite3 .connect (":memory:" )
285+ self .addCleanup (con .close )
276286
277287 def ask (cond ):
278288 c = cond
@@ -302,6 +312,7 @@ def test_host_length_code_final_equality(self):
302312 # (LENGTH(..)>n, UNICODE(..)>n) converges off-by-one; the '=' confirmation must fail closed
303313 # rather than hand back silently-wrong code-point text as exact.
304314 con = sqlite3 .connect (":memory:" )
315+ self .addCleanup (con .close )
305316 con .execute ("CREATE TABLE t (v TEXT)" )
306317 con .execute ("INSERT INTO t VALUES ('Admin-42')" )
307318 con .commit ()
@@ -329,6 +340,7 @@ def test_hex_unknown_codec_non_ascii_not_exact(self):
329340 # (e.g. utf-8 bytes with an embedded NUL heuristically read as UTF-16). Bytes are faithful;
330341 # only a PROVEN codec makes the decoded text exact.
331342 con = sqlite3 .connect (":memory:" )
343+ self .addCleanup (con .close )
332344 con .execute ("CREATE TABLE t (v TEXT)" )
333345 con .execute ("INSERT INTO t VALUES (?)" , (u"é" ,)) # utf-8 C3 A9 -> non-ASCII bytes
334346 con .execute ("CREATE TABLE a (v TEXT)" )
@@ -356,6 +368,7 @@ def test_bytelen_witness_fails_closed(self):
356368 # Round 8 #5: once a byte-length witness is selected, an UNDECIDED reading must reject the
357369 # bytes (fail closed), never treat "couldn't verify" as "matched".
358370 con = sqlite3 .connect (":memory:" )
371+ self .addCleanup (con .close )
359372 con .execute ("CREATE TABLE t (v TEXT)" )
360373 con .execute ("INSERT INTO t VALUES ('abc')" )
361374 con .commit ()
@@ -389,6 +402,7 @@ def test_lossy_cast_marked_inexact(self):
389402 # never ran on the very failure it defends against. The canary must run whenever a textcast
390403 # was applied, and an unproven cast must not certify source identity.
391404 con = sqlite3 .connect (":memory:" )
405+ self .addCleanup (con .close )
392406 con .execute ("CREATE TABLE t (id INTEGER PRIMARY KEY, v TEXT)" )
393407 con .execute (u"INSERT INTO t VALUES (1, 'café')" )
394408 con .commit ()
@@ -415,6 +429,7 @@ def test_repl_chars_escalate_to_hex(self):
415429 # the engine must escalate to the cast+hex path (which the framed dump proves works) and
416430 # recover the value exactly. Without hex, it stays honestly incomplete (no false-complete).
417431 con = sqlite3 .connect (":memory:" )
432+ self .addCleanup (con .close )
418433 con .execute ("CREATE TABLE t (v TEXT)" )
419434 con .execute (u"INSERT INTO t VALUES ('café-€')" )
420435 con .commit ()
@@ -466,6 +481,7 @@ def test_comparator_rejects_gte_rewrite(self):
466481 # False). the full truth table must reject 'gt' (and fall to BETWEEN) so counts/lengths
467482 # aren't read off-by-one. reproduced: extractInteger('5',max=10) used to return 6.
468483 con = sqlite3 .connect (":memory:" )
484+ self .addCleanup (con .close )
469485
470486 def ask (cond ):
471487 try :
@@ -481,6 +497,7 @@ def test_exact_requires_byte_witness(self):
481497 # without a proven hex/binary witness (or code-codepoint), a value is WHOLE_BUT_AMBIGUOUS,
482498 # never EXACT - plain '=' is collation-dependent and can't certify byte-exactness.
483499 con = sqlite3 .connect (":memory:" )
500+ self .addCleanup (con .close )
484501 con .execute ("CREATE TABLE t (v TEXT)" )
485502 con .execute ("INSERT INTO t VALUES ('Zz')" )
486503 con .commit ()
@@ -510,6 +527,7 @@ def test_extractresult_no_contradiction(self):
510527
511528 def test_host_maxlen_zero (self ):
512529 con = sqlite3 .connect (":memory:" )
530+ self .addCleanup (con .close )
513531 con .execute ("CREATE TABLE t (v TEXT)" )
514532 con .execute ("INSERT INTO t VALUES ('abcdef')" )
515533 con .commit ()
@@ -541,6 +559,7 @@ def test_integrity_semantics(self):
541559 # `complete` (walk finished) must be distinct from `exact` (bytes proven identical).
542560 # a case-insensitive collation recovers a WHOLE value that is NOT exact.
543561 con = sqlite3 .connect (":memory:" )
562+ self .addCleanup (con .close )
544563 con .execute ("CREATE TABLE t (v TEXT)" )
545564 con .execute ("INSERT INTO t VALUES ('A')" )
546565 con .commit ()
@@ -568,6 +587,7 @@ def test_hostextract_structured_and_tristate(self):
568587 # hostExtract returns an ExtractResult: a bounded read is TRUNCATED (not a bare string),
569588 # and an undecided (None) host observation degrades to a FAILED result, never a fake bit.
570589 con = sqlite3 .connect (":memory:" )
590+ self .addCleanup (con .close )
571591 con .execute ("CREATE TABLE t (v TEXT)" )
572592 con .execute ("INSERT INTO t VALUES ('abcdef')" )
573593 con .commit ()
@@ -602,6 +622,7 @@ def test_key_uniqueness_gate(self):
602622 # key's first column repeats -> `> prev` paging silently drops rows sharing it, so it
603623 # must be REJECTED (COUNT(*) != COUNT(DISTINCT col)); only a unique column is accepted.
604624 con = sqlite3 .connect (":memory:" )
625+ self .addCleanup (con .close )
605626 con .execute ("CREATE TABLE k (a INT, b INT, u INT, nul INT)" )
606627 con .executemany ("INSERT INTO k VALUES (?,?,?,?)" , [(1 , 1 , 10 , 1 ), (1 , 2 , 20 , None ), (2 , 1 , 30 , 3 )])
607628 con .commit ()
@@ -651,6 +672,7 @@ def test_coalesce(self):
651672
652673 def test_enumerate (self ):
653674 con = sqlite3 .connect (":memory:" )
675+ self .addCleanup (con .close )
654676 con .execute ("CREATE TABLE alpha (x)" )
655677 con .execute ("CREATE TABLE beta (y)" )
656678 con .commit ()
@@ -668,6 +690,7 @@ def ask(cond):
668690 def test_dump (self ):
669691 # row DATA byte-exact, including commas / quotes / unicode (hex framing keeps intact)
670692 con = sqlite3 .connect (":memory:" )
693+ self .addCleanup (con .close )
671694 con .execute ("CREATE TABLE users (id, uname, note)" )
672695 truth = [(1 , u"admin" , u"all,good" ), (2 , u"o'brien" , u"café,€" ), (3 , u"x" , u"" )]
673696 for row in truth :
@@ -692,6 +715,7 @@ def test_dump_scavenges_without_hex_or_concat(self):
692715 # extraction. Quotes/commas/NULLs in the data must survive (a single value has
693716 # no framing ambiguity). This is the scavenger's whole reason to exist.
694717 con = sqlite3 .connect (":memory:" )
718+ self .addCleanup (con .close )
695719 con .execute ("CREATE TABLE users (id INTEGER, name TEXT, email TEXT)" )
696720 for row in ((1 , "luther" , "a@b.c" ), (2 , "o'brien" , "x,y@z" ), (3 , "wu" , None )):
697721 con .execute ("INSERT INTO users VALUES (?,?,?)" , row )
@@ -723,6 +747,7 @@ def test_enumerate_without_count(self):
723747 # catalog detection, brute-force existence probing, and identifier quoting are
724748 # all COUNT-free (scalar-subquery existence), so tables/columns/dump still work.
725749 con = sqlite3 .connect (":memory:" )
750+ self .addCleanup (con .close )
726751 con .execute ("CREATE TABLE users (id INTEGER, name TEXT)" )
727752 con .execute ("INSERT INTO users VALUES (1, 'admin'), (2, 'root')" )
728753 con .commit ()
@@ -747,6 +772,7 @@ def ask(cond):
747772 def test_quoting (self ):
748773 # reserved-word / spaced column names must be quoted, not interpolated raw
749774 con = sqlite3 .connect (":memory:" )
775+ self .addCleanup (con .close )
750776 con .execute ('CREATE TABLE q (id INTEGER, "order" TEXT, "group by" TEXT)' )
751777 con .execute ('INSERT INTO q VALUES (1, ?, ?)' , ("a'b" , "x,y" ))
752778 con .commit ()
@@ -767,6 +793,7 @@ def ask(cond):
767793 def test_strategy_handoff (self ):
768794 # the frozen InferenceStrategy is a *sufficient* host interface, and immutable
769795 con = sqlite3 .connect (":memory:" )
796+ self .addCleanup (con .close )
770797 con .execute ("CREATE TABLE k (v TEXT)" )
771798 con .execute ("INSERT INTO k VALUES ('Str4t3gy!')" )
772799 con .commit ()
@@ -788,6 +815,7 @@ def ask(cond):
788815 def test_pattern_match_fallback (self ):
789816 # SUBSTR + LENGTH + hex + code fns ALL blacklisted -> pure GLOB/LIKE floor
790817 con = sqlite3 .connect (":memory:" )
818+ self .addCleanup (con .close )
791819 con .execute ("CREATE TABLE flag (id INTEGER, v TEXT)" )
792820 con .execute ("INSERT INTO flag VALUES (1, 'FLAG{no_SUBSTR_%_needed}')" )
793821 con .commit ()
@@ -812,6 +840,7 @@ def test_like_floor_escapes_wildcard_chars(self):
812840 # like 'all_products' must escape them (\_ ESCAPE '\'), not treat them as
813841 # match-anything. GLOB is blocked here to force LIKE (where '_'/'%' are magic).
814842 con = sqlite3 .connect (":memory:" )
843+ self .addCleanup (con .close )
815844 con .execute ("CREATE TABLE v (val TEXT)" )
816845 con .execute ("INSERT INTO v VALUES ('all_products')" )
817846 for t in ("all_products" , "wp_users" , "sales%2024" ): # '_'/'%' in identifiers
@@ -838,6 +867,7 @@ def ask(cond):
838867 def test_length_from_substring (self ):
839868 # every length fn blacklisted but SUBSTR present -> length derived from the end
840869 con = sqlite3 .connect (":memory:" )
870+ self .addCleanup (con .close )
841871 con .execute ("CREATE TABLE t6 (v TEXT)" )
842872 con .execute (u"INSERT INTO t6 VALUES ('Admin-42€')" )
843873 con .commit ()
@@ -859,6 +889,7 @@ def test_enumeration_degrades_not_crashes(self):
859889 # a permission/charset wall mid-walk (oracle can't decide the keyset bound)
860890 # must STOP with partial results, never crash with OracleUndecided
861891 con = sqlite3 .connect (":memory:" )
892+ self .addCleanup (con .close )
862893 for t in ("alpha" , "beta" , "gamma" ):
863894 con .execute ("CREATE TABLE %s (x)" % t )
864895 con .commit ()
@@ -884,6 +915,7 @@ def test_left_right_rung(self):
884915 # RIGHT( onto them (the same rewrite the disguised-dialect oracles use). Keeps the
885916 # test portable across SQLite builds while still exercising the real left_right rung.
886917 con = sqlite3 .connect (":memory:" )
918+ self .addCleanup (con .close )
887919 con .execute ("CREATE TABLE t7 (v TEXT)" )
888920 con .execute ("INSERT INTO t7 VALUES ('Zagreb-42')" )
889921 con .commit ()
@@ -1029,6 +1061,7 @@ def test_disguise_bracket_quoting_reserved_words(self):
10291061 seed = ('CREATE TABLE q (id INTEGER, "order" TEXT, "group" TEXT)' ,
10301062 "INSERT INTO q VALUES (1, ?, ?)" )
10311063 con = sqlite3 .connect (":memory:" )
1064+ self .addCleanup (con .close )
10321065 con .execute (seed [0 ]); con .execute (seed [1 ], ("a,b" , "x'y" )); con .commit ()
10331066 blk = re .compile (r'"|`' )
10341067
@@ -1050,6 +1083,7 @@ def test_disguise_lossy_charcode_escalates_to_hex(self):
10501083 # a first-byte charcode fn (MySQL-style ASCII) is lossy for non-ASCII; the
10511084 # engine must detect that and escalate to hex, recovering the bytes exactly
10521085 con = sqlite3 .connect (":memory:" )
1086+ self .addCleanup (con .close )
10531087 con .execute ("CREATE TABLE t (v TEXT)" )
10541088 con .execute (u"INSERT INTO t VALUES ('café-€')" ) # cafe-EUR
10551089 con .commit ()
@@ -1071,6 +1105,7 @@ def test_disguise_unicode_through_dialect(self):
10711105 # non-ASCII data recovered byte-exact even while the dialect is disguised
10721106 # (SUBSTR/MID/CHAR_LENGTH/LENGTH blocked -> SUBSTRING/LEN mapped to SQLite)
10731107 con = sqlite3 .connect (":memory:" )
1108+ self .addCleanup (con .close )
10741109 con .execute ("CREATE TABLE s (v TEXT)" )
10751110 con .execute (u"INSERT INTO s VALUES ('Zagreb-župa-€42')" ) # Zagreb-zupa-EUR42
10761111 con .commit ()
@@ -1091,5 +1126,13 @@ def ask(cond):
10911126 self .assertEqual (esp .extractText ("(SELECT v FROM s)" ), u"Zagreb-župa-€42" )
10921127
10931128
1129+ def tearDownModule ():
1130+ while _OPEN_CONNECTIONS :
1131+ try :
1132+ _OPEN_CONNECTIONS .pop ().close ()
1133+ except Exception :
1134+ pass
1135+
1136+
10941137if __name__ == "__main__" :
10951138 unittest .main (verbosity = 2 )
0 commit comments