@@ -216,10 +216,6 @@ class Completion(unittest.TestCase):
216216
217217 @classmethod
218218 def setUpClass (cls ):
219- _sqlite3 = import_module ("_sqlite3" )
220- if not hasattr (_sqlite3 , "SQLITE_KEYWORDS" ):
221- raise unittest .SkipTest ("unable to determine SQLite keywords" )
222-
223219 readline = import_module ("readline" )
224220 if readline .backend == "editline" :
225221 raise unittest .SkipTest ("libedit readline is not supported" )
@@ -229,12 +225,24 @@ def write_input(self, input_, env=None):
229225 import readline
230226 from sqlite3.__main__ import main
231227
228+ # Configure readline to ...:
229+ # - hide control sequences surrounding each candidate
230+ # - hide "Display all xxx possibilities? (y or n)"
231+ # - show candidates one per line
232232 readline.parse_and_bind("set colored-completion-prefix off")
233+ readline.parse_and_bind("set completion-query-items 0")
234+ readline.parse_and_bind("set page-completions off")
235+ readline.parse_and_bind("set completion-display-width 0")
236+
233237 main()
234238 """ )
235239 return run_pty (script , input_ , env )
236240
237241 def test_complete_sql_keywords (self ):
242+ _sqlite3 = import_module ("_sqlite3" )
243+ if not hasattr (_sqlite3 , "SQLITE_KEYWORDS" ):
244+ raise unittest .SkipTest ("unable to determine SQLite keywords" )
245+
238246 # List candidates starting with 'S', there should be multiple matches.
239247 input_ = b"S\t \t EL\t 1;\n .quit\n "
240248 output = self .write_input (input_ )
@@ -249,6 +257,103 @@ def test_complete_sql_keywords(self):
249257 self .assertIn (b"SELECT" , output )
250258 self .assertIn (b"(1,)" , output )
251259
260+ def test_complete_table_indexes_triggers_views (self ):
261+ input_ = textwrap .dedent ("""\
262+ CREATE TABLE _table (id);
263+ CREATE INDEX _index ON _table (id);
264+ CREATE TRIGGER _trigger BEFORE INSERT
265+ ON _table BEGIN SELECT 1; END;
266+ CREATE VIEW _view AS SELECT 1;
267+
268+ CREATE TEMP TABLE _temp_table (id);
269+ CREATE INDEX temp._temp_index ON _temp_table (id);
270+ CREATE TEMP TRIGGER _temp_trigger BEFORE INSERT
271+ ON _table BEGIN SELECT 1; END;
272+ CREATE TEMP VIEW _temp_view AS SELECT 1;
273+
274+ ATTACH ':memory:' AS attached;
275+ CREATE TABLE attached._attached_table (id);
276+ CREATE INDEX attached._attached_index ON _attached_table (id);
277+ CREATE TRIGGER attached._attached_trigger BEFORE INSERT
278+ ON _attached_table BEGIN SELECT 1; END;
279+ CREATE VIEW attached._attached_view AS SELECT 1;
280+
281+ SELECT id FROM _\t \t ta\t ;
282+ .quit\n """ ).encode ()
283+ output = self .write_input (input_ )
284+ lines = output .decode ().splitlines ()
285+ indices = [i for i , line in enumerate (lines )
286+ if line .startswith (self .PS1 )]
287+ start , end = indices [- 3 ], indices [- 2 ]
288+ candidates = [l .strip () for l in lines [start + 1 :end ]]
289+ self .assertEqual (candidates ,
290+ [
291+ "_attached_index" ,
292+ "_attached_table" ,
293+ "_attached_trigger" ,
294+ "_attached_view" ,
295+ "_index" ,
296+ "_table" ,
297+ "_temp_index" ,
298+ "_temp_table" ,
299+ "_temp_trigger" ,
300+ "_temp_view" ,
301+ "_trigger" ,
302+ "_view" ,
303+ ],
304+ )
305+
306+ def test_complete_columns (self ):
307+ input_ = textwrap .dedent ("""\
308+ CREATE TABLE _table (_col_table);
309+ CREATE TEMP TABLE _temp_table (_col_temp);
310+ ATTACH ':memory:' AS attached;
311+ CREATE TABLE attached._attached_table (_col_attached);
312+
313+ SELECT _col_\t \t ta\t FROM _table;
314+ .quit\n """ ).encode ()
315+ output = self .write_input (input_ )
316+ lines = output .decode ().splitlines ()
317+ indices = [
318+ i for i , line in enumerate (lines ) if line .startswith (self .PS1 )
319+ ]
320+ start , end = indices [- 3 ], indices [- 2 ]
321+ candidates = [l .strip () for l in lines [start + 1 :end ]]
322+
323+ self .assertEqual (
324+ candidates , ["_col_attached" , "_col_table" , "_col_temp" ]
325+ )
326+
327+ def test_complete_functions (self ):
328+ input_ = b"SELECT AV\t 1);\n .quit\n "
329+ output = self .write_input (input_ )
330+ self .assertIn (b"AVG(1);" , output )
331+ self .assertIn (b"(1.0,)" , output )
332+
333+ # Functions are completed in upper case for even lower case user input.
334+ input_ = b"SELECT av\t 1);\n .quit\n "
335+ output = self .write_input (input_ )
336+ self .assertIn (b"AVG(1);" , output )
337+ self .assertIn (b"(1.0,)" , output )
338+
339+ def test_complete_schemata (self ):
340+ input_ = textwrap .dedent ("""\
341+ ATTACH ':memory:' AS _attached;
342+ CREATE TEMP TABLE _table (id);
343+
344+ SELECT * FROM \t \t _att\t .sqlite_master;
345+ .quit\n """ ).encode ()
346+ output = self .write_input (input_ )
347+ lines = output .decode ().splitlines ()
348+ indices = [
349+ i for i , line in enumerate (lines ) if line .startswith (self .PS1 )
350+ ]
351+ start , end = indices [- 3 ], indices [- 2 ]
352+ candidates = [l .strip () for l in lines [start + 1 :end ]]
353+ self .assertIn ("_attached" , candidates )
354+ self .assertIn ("main" , candidates )
355+ self .assertIn ("temp" , candidates )
356+
252357 @unittest .skipIf (sys .platform .startswith ("freebsd" ),
253358 "Two actual tabs are inserted when there are no matching"
254359 " completions in the pseudo-terminal opened by run_pty()"
@@ -269,8 +374,6 @@ def test_complete_no_match(self):
269374 self .assertEqual (line_num , len (lines ))
270375
271376 def test_complete_no_input (self ):
272- from _sqlite3 import SQLITE_KEYWORDS
273-
274377 script = textwrap .dedent ("""
275378 import readline
276379 from sqlite3.__main__ import main
@@ -301,7 +404,7 @@ def test_complete_no_input(self):
301404 self .assertEqual (len (indices ), 2 )
302405 start , end = indices
303406 candidates = [l .strip () for l in lines [start + 1 :end ]]
304- self .assertEqual (candidates , sorted (SQLITE_KEYWORDS ))
407+ self .assertEqual (candidates , sorted (candidates ))
305408 except :
306409 if verbose :
307410 print (' PTY output: ' .center (30 , '-' ))
0 commit comments