@ -1,7 +1,11 @@
import testsamples
import datetime
import test_engine
import testsamples
from autocomplete_context import repr_example , eval_suggestion
from schema import RecalcWhen
class TestCompletion ( test_engine . EngineTestCase ) :
user = {
' Name ' : ' Foo ' ,
@ -34,85 +38,89 @@ class TestCompletion(test_engine.EngineTestCase):
type = " Text " , isFormula = False , formula = " foo@getgrist.com " ,
recalcWhen = RecalcWhen . MANUAL_UPDATES
)
self . update_record ( ' Schools ' , 3 , budget = ' 123.45 ' , yearFounded = ' 2010 ' , lastModified = ' 2018-01-01 ' )
self . update_record ( ' Students ' , 1 , homeAddress = 11 , school = 1 )
# Create a summary table of Students grouped by school
self . apply_user_action ( [ " CreateViewSection " , 1 , 0 , " record " , [ 22 ] , None ] )
def test_keyword ( self ) :
self . assertEqual ( self . engine . autocomplete ( " for " , " Address " , " city " , self . user ) ,
self . assertEqual ( self . autocomplete( " for " , " Address " , " city " ) ,
[ " for " , " format( " ] )
def test_grist ( self ) :
self . assertEqual ( self . engine. autocomplete( " gri " , " Address " , " city " , self . user ) ,
self . assertEqual ( self . autocomplete( " gri " , " Address " , " city " ) ,
[ " grist " ] )
def test_value ( self ) :
# Should only appear if column exists and is a trigger formula.
self . assertEqual (
self . engine. autocomplete( " val " , " Schools " , " lastModified " , self . user ) ,
self . autocomplete( " val " , " Schools " , " lastModified " ) ,
[ " value " ]
)
self . assertEqual (
self . engine. autocomplete( " val " , " Students " , " schoolCities " , self . user ) ,
self . autocomplete( " val " , " Students " , " schoolCities " ) ,
[ ]
)
self . assertEqual (
self . engine. autocomplete( " val " , " Students " , " nonexistentColumn " , self . user ) ,
self . autocomplete( " val " , " Students " , " nonexistentColumn " ) ,
[ ]
)
self . assertEqual ( self . engine. autocomplete( " valu " , " Schools " , " lastModifier " , self . user ) ,
self . assertEqual ( self . autocomplete( " valu " , " Schools " , " lastModifier " ) ,
[ " value " ] )
# Should have same type as column.
self . assertGreaterEqual (
set ( self . engine. autocomplete( " value. " , " Schools " , " lastModifier " , self . user ) ) ,
set ( self . autocomplete( " value. " , " Schools " , " lastModifier " ) ) ,
{ ' value.startswith( ' , ' value.replace( ' , ' value.title( ' }
)
self . assertGreaterEqual (
set ( self . engine. autocomplete( " value. " , " Schools " , " lastModified " , self . user ) ) ,
set ( self . autocomplete( " value. " , " Schools " , " lastModified " ) ) ,
{ ' value.month ' , ' value.strftime( ' , ' value.replace( ' }
)
self . assertGreaterEqual (
set ( self . engine. autocomplete( " value.m " , " Schools " , " lastModified " , self . user ) ) ,
set ( self . autocomplete( " value.m " , " Schools " , " lastModified " ) ) ,
{ ' value.month ' , ' value.minute ' }
)
def test_user ( self ) :
# Should only appear if column exists and is a trigger formula.
self . assertEqual ( self . engine. autocomplete( " use " , " Schools " , " lastModified " , self . user ) ,
self . assertEqual ( self . autocomplete( " use " , " Schools " , " lastModified " ) ,
[ " user " ] )
self . assertEqual ( self . engine. autocomplete( " use " , " Students " , " schoolCities " , self . user ) ,
self . assertEqual ( self . autocomplete( " use " , " Students " , " schoolCities " ) ,
[ ] )
self . assertEqual ( self . engine. autocomplete( " use " , " Students " , " nonexistentColumn " , self . user ) ,
self . assertEqual ( self . autocomplete( " use " , " Students " , " nonexistentColumn " ) ,
[ ] )
self . assertEqual ( self . engine. autocomplete( " user " , " Schools " , " lastModifier " , self . user ) ,
self . assertEqual ( self . autocomplete( " user " , " Schools " , " lastModifier " ) ,
[ " user " ] )
self . assertEqual (
self . engine. autocomplete( " user. " , " Schools " , " lastModified " , self . user ) ,
self . autocomplete( " user. " , " Schools " , " lastModified " , row_id = 2 ) ,
[
' user.Access ' ,
' user.Email ' ,
' user.IsLoggedIn ' ,
' user.LinkKey ' ,
' user.Name ' ,
' user.Origin ' ,
' user.SessionID ' ,
' user.StudentInfo ' ,
' user.UserID '
( ' user.Access ' , " ' owners ' " ) ,
( ' user.Email ' , " ' foo@example.com ' " ) ,
( ' user.IsLoggedIn ' , ' True ' ) ,
( ' user.LinkKey ' , None ) ,
( ' user.Name ' , " ' Foo ' " ) ,
( ' user.Origin ' , ' None ' ) ,
( ' user.SessionID ' , " ' u1 ' " ) ,
( ' user.StudentInfo ' , ' Students[1] ' ) ,
( ' user.UserID ' , ' 1 ' ) ,
]
)
# Should follow user attribute references and autocomplete those types.
self . assertEqual (
self . engine. autocomplete( " user.StudentInfo. " , " Schools " , " lastModified " , self . user ) ,
self . autocomplete( " user.StudentInfo. " , " Schools " , " lastModified " , row_id = 2 ) ,
[
' user.StudentInfo.birthDate ' ,
' user.StudentInfo.firstName ' ,
' user.StudentInfo.homeAddress ' ,
' user.StudentInfo.homeAddress.city ' ,
' user.StudentInfo.id ' ,
' user.StudentInfo.lastName ' ,
' user.StudentInfo.lastVisit ' ,
' user.StudentInfo.school ' ,
' user.StudentInfo.school.name ' ,
' user.StudentInfo.schoolCities ' ,
' user.StudentInfo.schoolIds ' ,
' user.StudentInfo.schoolName '
( ' user.StudentInfo.birthDate ' , ' None ' ) ,
( ' user.StudentInfo.firstName ' , " ' Barack ' " ) ,
( ' user.StudentInfo.homeAddress ' , ' Address[11] ' ) ,
( ' user.StudentInfo.homeAddress.city ' , " ' New York ' " ) ,
( ' user.StudentInfo.id ' , ' 1 ' ) ,
( ' user.StudentInfo.lastName ' , " ' Obama ' " ) ,
( ' user.StudentInfo.lastVisit ' , ' None ' ) ,
( ' user.StudentInfo.school ' , ' Schools[1] ' ) ,
( ' user.StudentInfo.school.name ' , " ' Columbia ' " ) ,
( ' user.StudentInfo.schoolCities ' , repr ( u ' New York:Colombia ' ) ) ,
( ' user.StudentInfo.schoolIds ' , repr ( u ' 1:2 ' ) ) ,
( ' user.StudentInfo.schoolName ' , " ' Columbia ' " ) ,
]
)
# Should not show user attribute completions if user doesn't have attribute.
@ -127,27 +135,27 @@ class TestCompletion(test_engine.EngineTestCase):
' IsLoggedIn ' : True
}
self . assertEqual (
self . engine. autocomplete( " user. " , " Schools " , " lastModified " , user 2) ,
self . autocomplete( " user. " , " Schools " , " lastModified " , user 2, row_id = 2) ,
[
' user.Access ' ,
' user.Email ' ,
' user.IsLoggedIn ' ,
' user.LinkKey ' ,
' user.Name ' ,
' user.Origin ' ,
' user.SessionID ' ,
' user.UserID '
( ' user.Access ' , " ' owners ' " ) ,
( ' user.Email ' , " ' baro@example.com ' " ) ,
( ' user.IsLoggedIn ' , ' True ' ) ,
( ' user.LinkKey ' , None ) ,
( ' user.Name ' , " ' Bar ' " ) ,
( ' user.Origin ' , ' None ' ) ,
( ' user.SessionID ' , " ' u2 ' " ) ,
( ' user.UserID ' , ' 2 ' ) ,
]
)
self . assertEqual (
self . engine. autocomplete( " user.StudentInfo. " , " Schools " , " schoolCities " , user2 ) ,
self . autocomplete( " user.StudentInfo. " , " Schools " , " schoolCities " , user2 ) ,
[ ]
)
def test_function ( self ) :
self . assertEqual ( self . engine. autocomplete( " MEDI " , " Address " , " city " , self . user ) ,
self . assertEqual ( self . autocomplete( " MEDI " , " Address " , " city " ) ,
[ ( ' MEDIAN ' , ' (value, *more_values) ' , True ) ] )
self . assertEqual ( self . engine. autocomplete( " ma " , " Address " , " city " , self . user ) , [
self . assertEqual ( self . autocomplete( " ma " , " Address " , " city " ) , [
( ' MAX ' , ' (value, *more_values) ' , True ) ,
( ' MAXA ' , ' (value, *more_values) ' , True ) ,
' map( ' ,
@ -156,31 +164,34 @@ class TestCompletion(test_engine.EngineTestCase):
] )
def test_member ( self ) :
self . assertEqual ( self . engine. autocomplete( " datetime.tz " , " Address " , " city " , self . user ) ,
self . assertEqual ( self . autocomplete( " datetime.tz " , " Address " , " city " ) ,
[ " datetime.tzinfo( " ] )
def test_case_insensitive ( self ) :
self . assertEqual ( self . engine. autocomplete( " medi " , " Address " , " city " , self . user ) ,
self . assertEqual ( self . autocomplete( " medi " , " Address " , " city " ) ,
[ ( ' MEDIAN ' , ' (value, *more_values) ' , True ) ] )
self . assertEqual ( self . engine. autocomplete( " std " , " Address " , " city " , self . user ) , [
self . assertEqual ( self . autocomplete( " std " , " Address " , " city " ) , [
( ' STDEV ' , ' (value, *more_values) ' , True ) ,
( ' STDEVA ' , ' (value, *more_values) ' , True ) ,
( ' STDEVP ' , ' (value, *more_values) ' , True ) ,
( ' STDEVPA ' , ' (value, *more_values) ' , True )
] )
self . assertEqual (
self . engine. autocomplete( " stu " , " Address " , " city " , self . user ) ,
self . autocomplete( " stu " , " Address " , " city " ) ,
[
' Students ' ,
( ' Students.lookupOne ' , ' (colName=<value>, ...) ' , True ) ,
( ' Students.lookupRecords ' , ' (colName=<value>, ...) ' , True ) ,
' Students.lookupRecords(homeAddress=$id) ' ,
' Students_summary_school ' ,
( ' Students_summary_school.lookupOne ' , ' (colName=<value>, ...) ' , True ) ,
( ' Students_summary_school.lookupRecords ' , ' (colName=<value>, ...) ' , True )
] ,
)
# Add a table name whose lowercase version conflicts with a builtin.
self . apply_user_action ( [ ' AddTable ' , ' Max ' , [ ] ] )
self . assertEqual ( self . engine. autocomplete( " max " , " Address " , " city " , self . user ) , [
self . assertEqual ( self . autocomplete( " max " , " Address " , " city " ) , [
( ' MAX ' , ' (value, *more_values) ' , True ) ,
( ' MAXA ' , ' (value, *more_values) ' , True ) ,
' Max ' ,
@ -188,7 +199,7 @@ class TestCompletion(test_engine.EngineTestCase):
( ' Max.lookupRecords ' , ' (colName=<value>, ...) ' , True ) ,
' max( ' ,
] )
self . assertEqual ( self . engine. autocomplete( " MAX " , " Address " , " city " , self . user ) , [
self . assertEqual ( self . autocomplete( " MAX " , " Address " , " city " ) , [
( ' MAX ' , ' (value, *more_values) ' , True ) ,
( ' MAXA ' , ' (value, *more_values) ' , True ) ,
] )
@ -196,23 +207,23 @@ class TestCompletion(test_engine.EngineTestCase):
def test_suggest_globals_and_tables ( self ) :
# Should suggest globals and table names.
self . assertEqual ( self . engine. autocomplete( " ME " , " Address " , " city " , self . user ) ,
self . assertEqual ( self . autocomplete( " ME " , " Address " , " city " ) ,
[ ( ' MEDIAN ' , ' (value, *more_values) ' , True ) ] )
self . assertEqual (
self . engine. autocomplete( " Ad " , " Address " , " city " , self . user ) ,
self . autocomplete( " Ad " , " Address " , " city " ) ,
[
' Address ' ,
( ' Address.lookupOne ' , ' (colName=<value>, ...) ' , True ) ,
( ' Address.lookupRecords ' , ' (colName=<value>, ...) ' , True ) ,
] ,
)
self . assertGreaterEqual ( set ( self . engine. autocomplete( " S " , " Address " , " city " , self . user ) ) , {
self . assertGreaterEqual ( set ( self . autocomplete( " S " , " Address " , " city " ) ) , {
' Schools ' ,
' Students ' ,
( ' SUM ' , ' (value1, *more_values) ' , True ) ,
( ' STDEV ' , ' (value, *more_values) ' , True ) ,
} )
self . assertGreaterEqual ( set ( self . engine. autocomplete( " s " , " Address " , " city " , self . user ) ) , {
self . assertGreaterEqual ( set ( self . autocomplete( " s " , " Address " , " city " ) ) , {
' Schools ' ,
' Students ' ,
' sum( ' ,
@ -220,7 +231,7 @@ class TestCompletion(test_engine.EngineTestCase):
( ' STDEV ' , ' (value, *more_values) ' , True ) ,
} )
self . assertEqual (
self . engine. autocomplete( " Addr " , " Schools " , " budget " , self . user ) ,
self . autocomplete( " Addr " , " Schools " , " budget " ) ,
[
' Address ' ,
( ' Address.lookupOne ' , ' (colName=<value>, ...) ' , True ) ,
@ -229,26 +240,26 @@ class TestCompletion(test_engine.EngineTestCase):
)
def test_suggest_columns ( self ) :
self . assertEqual ( self . engine. autocomplete( " $ci " , " Address " , " city " , self . user ) ,
self . assertEqual ( self . autocomplete( " $ci " , " Address " , " city " ) ,
[ " $city " ] )
self . assertEqual ( self . engine. autocomplete( " rec.i " , " Address " , " city " , self . user ) ,
self . assertEqual ( self . autocomplete( " rec.i " , " Address " , " city " ) ,
[ " rec.id " ] )
self . assertEqual ( len ( self . engine. autocomplete( " $ " , " Address " , " city " , self . user ) ) ,
self . assertEqual ( len ( self . autocomplete( " $ " , " Address " , " city " ) ) ,
2 )
# A few more detailed examples.
self . assertEqual ( self . engine. autocomplete( " $ " , " Students " , " school " , self . user ) ,
self . assertEqual ( self . autocomplete( " $ " , " Students " , " school " ) ,
[ ' $birthDate ' , ' $firstName ' , ' $homeAddress ' , ' $homeAddress.city ' ,
' $id ' , ' $lastName ' , ' $lastVisit ' ,
' $school ' , ' $school.name ' , ' $schoolCities ' , ' $schoolIds ' , ' $schoolName ' ] )
self . assertEqual ( self . engine. autocomplete( " $fi " , " Students " , " birthDate " , self . user ) ,
self . assertEqual ( self . autocomplete( " $fi " , " Students " , " birthDate " ) ,
[ ' $firstName ' ] )
self . assertEqual ( self . engine. autocomplete( " $school " , " Students " , " lastVisit " , self . user ) ,
self . assertEqual ( self . autocomplete( " $school " , " Students " , " lastVisit " ) ,
[ ' $school ' , ' $school.name ' , ' $schoolCities ' , ' $schoolIds ' , ' $schoolName ' ] )
def test_suggest_lookup_methods ( self ) :
# Should suggest lookup formulas for tables.
address_dot_completion = self . engine. autocomplete( " Address. " , " Students " , " firstName " , self . user )
address_dot_completion = self . autocomplete( " Address. " , " Students " , " firstName " )
# In python 3.9.7, rlcompleter stops adding parens for property attributes,
# see https://bugs.python.org/issue44752 - seems like a minor issue, so leave test
# tolerant.
@ -262,7 +273,7 @@ class TestCompletion(test_engine.EngineTestCase):
] )
self . assertEqual (
self . engine. autocomplete( " Address.lookup " , " Students " , " lastName " , self . user ) ,
self . autocomplete( " Address.lookup " , " Students " , " lastName " ) ,
[
( ' Address.lookupOne ' , ' (colName=<value>, ...) ' , True ) ,
( ' Address.lookupRecords ' , ' (colName=<value>, ...) ' , True ) ,
@ -270,7 +281,7 @@ class TestCompletion(test_engine.EngineTestCase):
)
self . assertEqual (
self . engine. autocomplete( " address.look " , " Students " , " schoolName " , self . user ) ,
self . autocomplete( " address.look " , " Students " , " schoolName " ) ,
[
( ' Address.lookupOne ' , ' (colName=<value>, ...) ' , True ) ,
( ' Address.lookupRecords ' , ' (colName=<value>, ...) ' , True ) ,
@ -280,25 +291,25 @@ class TestCompletion(test_engine.EngineTestCase):
def test_suggest_column_type_methods ( self ) :
# Should treat columns as correct types.
self . assertGreaterEqual (
set ( self . engine. autocomplete( " $firstName. " , " Students " , " firstName " , self . user ) ) ,
set ( self . autocomplete( " $firstName. " , " Students " , " firstName " ) ) ,
{ ' $firstName.startswith( ' , ' $firstName.replace( ' , ' $firstName.title( ' }
)
self . assertGreaterEqual (
set ( self . engine. autocomplete( " $birthDate. " , " Students " , " lastName " , self . user ) ) ,
set ( self . autocomplete( " $birthDate. " , " Students " , " lastName " ) ) ,
{ ' $birthDate.month ' , ' $birthDate.strftime( ' , ' $birthDate.replace( ' }
)
self . assertGreaterEqual (
set ( self . engine. autocomplete( " $lastVisit.m " , " Students " , " firstName " , self . user ) ) ,
set ( self . autocomplete( " $lastVisit.m " , " Students " , " firstName " ) ) ,
{ ' $lastVisit.month ' , ' $lastVisit.minute ' }
)
self . assertGreaterEqual (
set ( self . engine. autocomplete( " $school. " , " Students " , " firstName " , self . user ) ) ,
set ( self . autocomplete( " $school. " , " Students " , " firstName " ) ) ,
{ ' $school.address ' , ' $school.name ' , ' $school.yearFounded ' , ' $school.budget ' }
)
self . assertEqual ( self . engine. autocomplete( " $school.year " , " Students " , " lastName " , self . user ) ,
self . assertEqual ( self . autocomplete( " $school.year " , " Students " , " lastName " ) ,
[ ' $school.yearFounded ' ] )
self . assertGreaterEqual (
set ( self . engine. autocomplete( " $yearFounded. " , " Schools " , " budget " , self . user ) ) ,
set ( self . autocomplete( " $yearFounded. " , " Schools " , " budget " ) ) ,
{
' $yearFounded.denominator ' , # Only integers have this
' $yearFounded.bit_length( ' , # and this
@ -306,18 +317,18 @@ class TestCompletion(test_engine.EngineTestCase):
}
)
self . assertGreaterEqual (
set ( self . engine. autocomplete( " $budget. " , " Schools " , " budget " , self . user ) ) ,
set ( self . autocomplete( " $budget. " , " Schools " , " budget " ) ) ,
{ ' $budget.is_integer( ' , ' $budget.real ' } # Only floats have this
)
def test_suggest_follows_references ( self ) :
# Should follow references and autocomplete those types.
self . assertEqual (
self . engine. autocomplete( " $school.name.st " , " Students " , " firstName " , self . user ) ,
self . autocomplete( " $school.name.st " , " Students " , " firstName " ) ,
[ ' $school.name.startswith( ' , ' $school.name.strip( ' ]
)
self . assertGreaterEqual (
set ( self . engine. autocomplete( " $school.yearFounded. " , " Students " , " firstName " , self . user ) ) ,
set ( self . autocomplete( " $school.yearFounded. " , " Students " , " firstName " ) ) ,
{
' $school.yearFounded.denominator ' ,
' $school.yearFounded.bit_length( ' ,
@ -326,11 +337,11 @@ class TestCompletion(test_engine.EngineTestCase):
)
self . assertEqual (
self . engine. autocomplete( " $school.address. " , " Students " , " lastName " , self . user ) ,
self . autocomplete( " $school.address. " , " Students " , " lastName " ) ,
[ ' $school.address.city ' , ' $school.address.id ' ]
)
self . assertEqual (
self . engine. autocomplete( " $school.address.city.st " , " Students " , " lastName " , self . user ) ,
self . autocomplete( " $school.address.city.st " , " Students " , " lastName " ) ,
[ ' $school.address.city.startswith( ' , ' $school.address.city.strip( ' ]
)
@ -339,17 +350,21 @@ class TestCompletion(test_engine.EngineTestCase):
# including a 'reverse reference' lookup, i.e. `<refcol to current table>=$id`,
# but only for `lookupRecords`, not `lookupOne`.
self . assertEqual (
self . engine. autocomplete( " stu " , " Schools " , " name " , self . user ) ,
self . autocomplete( " stu " , " Schools " , " name " ) ,
[
' Students ' ,
( ' Students.lookupOne ' , ' (colName=<value>, ...) ' , True ) ,
( ' Students.lookupRecords ' , ' (colName=<value>, ...) ' , True ) ,
# i.e. Students.school is a reference to Schools
' Students.lookupRecords(school=$id) ' ,
' Students_summary_school ' ,
( ' Students_summary_school.lookupOne ' , ' (colName=<value>, ...) ' , True ) ,
( ' Students_summary_school.lookupRecords ' , ' (colName=<value>, ...) ' , True ) ,
' Students_summary_school.lookupRecords(school=$id) ' ,
] ,
)
self . assertEqual (
self . engine . autocomplete ( " scho " , " Address " , " city " , self . user ) ,
self . autocomplete( " scho " , " Address " , " city " ) ,
[
' Schools ' ,
( ' Schools.lookupOne ' , ' (colName=<value>, ...) ' , True ) ,
@ -362,7 +377,7 @@ class TestCompletion(test_engine.EngineTestCase):
# Same as above, but the formula is being entered in 'Students' instead of 'Address',
# which means there's no reverse reference to suggest.
self . assertEqual (
self . engine. autocomplete( " scho " , " Students " , " firstName " , self . user ) ,
self . autocomplete( " scho " , " Students " , " firstName " ) ,
[
' Schools ' ,
( ' Schools.lookupOne ' , ' (colName=<value>, ...) ' , True ) ,
@ -370,11 +385,24 @@ class TestCompletion(test_engine.EngineTestCase):
] ,
)
# Test from within a summary table
self . assertEqual (
self . autocomplete ( " stu " , " Students_summary_school " , " count " ) ,
[
' Students ' ,
( ' Students.lookupOne ' , ' (colName=<value>, ...) ' , True ) ,
( ' Students.lookupRecords ' , ' (colName=<value>, ...) ' , True ) ,
' Students_summary_school ' ,
( ' Students_summary_school.lookupOne ' , ' (colName=<value>, ...) ' , True ) ,
( ' Students_summary_school.lookupRecords ' , ' (colName=<value>, ...) ' , True ) ,
] ,
)
def test_suggest_lookup_arguments ( self ) :
# Typing in the full `.lookupRecords(` should suggest keyword argument (i.e. column) names,
# in addition to reference lookups, including the reverse reference lookups above.
self . assertEqual (
self . engine . autocomplete ( " Schools.lookupRecords( " , " Address " , " city " , self . user ) ,
self . autocomplete( " Schools.lookupRecords( " , " Address " , " city " ) ,
[
' Schools.lookupRecords(address= ' ,
' Schools.lookupRecords(address=$id) ' ,
@ -391,7 +419,7 @@ class TestCompletion(test_engine.EngineTestCase):
# columns (one from the looked up table, one from the current table) targeting the same table,
# e.g. `address=$homeAddress` in the two cases below.
self . assertEqual (
self . engine. autocomplete( " Schools.lookupRecords( " , " Students " , " firstName " , self . user ) ,
self . autocomplete( " Schools.lookupRecords( " , " Students " , " firstName " ) ,
[
' Schools.lookupRecords(address= ' ,
' Schools.lookupRecords(address=$homeAddress) ' ,
@ -405,7 +433,7 @@ class TestCompletion(test_engine.EngineTestCase):
)
self . assertEqual (
self . engine. autocomplete( " Students.lookupRecords( " , " Schools " , " name " , self . user ) ,
self . autocomplete( " Students.lookupRecords( " , " Schools " , " name " ) ,
[
' Students.lookupRecords(birthDate= ' ,
' Students.lookupRecords(firstName= ' ,
@ -430,7 +458,7 @@ class TestCompletion(test_engine.EngineTestCase):
# This doesn't affect anything, because there's no way to do the opposite of CONTAINS()
self . add_column ( ' Schools ' , ' otherAddresses ' , type = ' RefList:Address ' )
self . assertEqual (
self . engine. autocomplete( " Students.lookupRecords( " , " Schools " , " name " , self . user ) ,
self . autocomplete( " Students.lookupRecords( " , " Schools " , " name " ) ,
[
' Students.lookupRecords(birthDate= ' ,
' Students.lookupRecords(firstName= ' ,
@ -453,3 +481,163 @@ class TestCompletion(test_engine.EngineTestCase):
' Students.lookupRecords(schoolName= ' ,
] ,
)
def autocomplete ( self , formula , table , column , user = None , row_id = None ) :
"""
Mild convenience over self . engine . autocomplete .
Only returns suggestions without example values , unless row_id is specified .
"""
user = user or self . user
results = self . engine . autocomplete ( formula , table , column , row_id or 1 , user )
if row_id is None :
return [ result for result , value in results ]
else :
return results
def test_example_values ( self ) :
self . assertEqual (
self . autocomplete ( " $ " , " Schools " , " name " , row_id = 1 ) ,
[
( ' $address ' , ' Address[11] ' ) ,
( ' $budget ' , ' 0.0 ' ) ,
( ' $id ' , ' 1 ' ) ,
( ' $lastModified ' , ' None ' ) ,
( ' $lastModifier ' , repr ( u ' ' ) ) ,
( ' $name ' , " ' Columbia ' " ) ,
( ' $yearFounded ' , ' 0 ' ) ,
] ,
)
self . assertEqual (
self . autocomplete ( " $ " , " Schools " , " name " , row_id = 3 ) ,
[
( ' $address ' , ' Address[13] ' ) ,
( ' $budget ' , ' 123.45 ' ) ,
( ' $id ' , ' 3 ' ) ,
( ' $lastModified ' , ' 2018-01-01 12:00am ' ) ,
( ' $lastModifier ' , None ) ,
( ' $name ' , " ' Yale ' " ) ,
( ' $yearFounded ' , ' 2010 ' ) ,
] ,
)
self . assertEqual (
self . autocomplete ( " $ " , " Address " , " name " , row_id = 1 ) ,
[
( ' $city ' , repr ( u ' ' ) ) , # for Python 2/3 compatibility
( ' $id ' , ' 0 ' ) , # row_id 1 doesn't exist!
] ,
)
self . assertEqual (
self . autocomplete ( " $ " , " Address " , " name " , row_id = 11 ) ,
[
( ' $city ' , " ' New York ' " ) ,
( ' $id ' , ' 11 ' ) ,
] ,
)
self . assertEqual (
self . autocomplete ( " $ " , " Address " , " name " , row_id = ' new ' ) ,
[
( ' $city ' , " ' West Haven ' " ) ,
( ' $id ' , ' 14 ' ) , # row_id 'new' gets replaced with the maximum row ID in the table
] ,
)
self . assertEqual (
self . autocomplete ( " $ " , " Students " , " name " , row_id = 1 ) ,
[
( ' $birthDate ' , ' None ' ) ,
( ' $firstName ' , " ' Barack ' " ) ,
( ' $homeAddress ' , ' Address[11] ' ) ,
( ' $homeAddress.city ' , " ' New York ' " ) ,
( ' $id ' , ' 1 ' ) ,
( ' $lastName ' , " ' Obama ' " ) ,
( ' $lastVisit ' , ' None ' ) ,
( ' $school ' , ' Schools[1] ' ) ,
( ' $school.name ' , " ' Columbia ' " ) ,
( ' $schoolCities ' , repr ( u ' New York:Colombia ' ) ) ,
( ' $schoolIds ' , repr ( u ' 1:2 ' ) ) ,
( ' $schoolName ' , " ' Columbia ' " ) ,
] ,
)
self . assertEqual (
self . autocomplete ( " rec " , " Students " , " name " , row_id = 1 ) ,
[
# Mixture of suggestions with and without values
( ( ' RECORD ' , ' (record_or_list, dates_as_iso=False, expand_refs=0) ' , True ) , None ) ,
( ' rec ' , ' Students[1] ' ) ,
] ,
)
def test_repr ( self ) :
date = datetime . date ( 2019 , 12 , 31 )
dtime = datetime . datetime ( 2019 , 12 , 31 , 13 , 23 )
self . assertEqual ( repr_example ( date ) , " 2019-12-31 " )
self . assertEqual ( repr_example ( dtime ) , " 2019-12-31 1:23pm " )
self . assertEqual ( repr_example ( [ 1 , ' a ' , dtime , date ] ) ,
" [1, ' a ' , 2019-12-31 1:23pm, 2019-12-31] " )
prefix = " <BadRepr instance at 0x "
self . assertEqual ( repr_example ( BadRepr ( ) ) [ : len ( prefix ) ] , prefix )
big_list = [ 9 ] * 100000
self . assertEqual ( len ( big_list ) , 100000 )
big_list_repr = repr_example ( big_list )
self . assertEqual ( len ( big_list_repr ) , 605 )
self . assertEqual ( big_list_repr , " [ %s ...] " % ( " 9, " * 200 ) )
def test_eval_suggestion ( self ) :
class Record ( object ) :
def __init__ ( self , name ) :
self . name = name
def __repr__ ( self ) :
return " Record( %s ) " % self . name
@property
def bad ( self ) :
raise Exception ( " bad " )
rec = Record ( ' rec ' )
rec . subrec = Record ( ' subrec ' )
rec . subrec . meaning = 42
rec . bad_repr = BadRepr ( )
rec . big = " a " * 100000
user = Record ( ' user ' )
user . email = ' my_email '
user . LinkKey = Record ( ' LinkKey ' )
user . LinkKey . id = 123
self . assertEqual ( eval_suggestion ( ' rec ' , rec , user ) , ' Record(rec) ' )
self . assertEqual ( eval_suggestion ( ' rec.subrec ' , rec , user ) , ' Record(subrec) ' )
self . assertEqual ( eval_suggestion ( ' rec.subrec.meaning ' , rec , user ) , ' 42 ' )
self . assertEqual ( eval_suggestion ( ' rec.spam ' , rec , user ) , None ) # doesn't exist
self . assertEqual ( eval_suggestion ( ' rec.bad ' , rec , user ) , None ) # property raises an error
# attribute exists, but repr() raises an error
prefix = " <BadRepr instance at 0x "
self . assertEqual ( eval_suggestion ( ' rec.bad_repr ' , rec , user ) [ : len ( prefix ) ] , prefix )
# attribute exists, but repr() is too long and gets truncated
big_repr = repr_example ( rec . big )
self . assertEqual ( eval_suggestion ( ' rec.big ' , rec , user ) , big_repr )
self . assertEqual ( len ( big_repr ) , 200 )
# No string representations for these two
self . assertEqual ( eval_suggestion ( ' user ' , rec , user ) , None )
self . assertEqual ( eval_suggestion ( ' user.LinkKey ' , rec , user ) , None )
self . assertEqual ( eval_suggestion ( ' user.email ' , rec , user ) , " ' my_email ' " )
self . assertEqual ( eval_suggestion ( ' user.LinkKey.id ' , rec , user ) , ' 123 ' )
self . assertEqual ( eval_suggestion ( ' user.spam ' , rec , user ) , None ) # doesn't exist
self . assertEqual ( eval_suggestion ( ' user.bad ' , rec , user ) , None ) # property raises an error
self . assertEqual ( eval_suggestion ( ' subrec ' , rec , user ) , None ) # other variables not supported
class BadRepr ( object ) :
def __repr__ ( self ) :
raise Exception ( " Bad repr " )