mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
a9d5b4d5af
Summary: Dealing with some things that bothered and sometimes confused me: Make Table.Record[Set] provide the table argument automatically Remove the classes from UserTable because they're not used anywhere and the Table/UserTable distinction is already confusing. They're not documented for users and they don't show up in autocomplete. Remove RecordSet.Record because it was confusing me where that attribute was being set, but also this means .Record will work properly for users with columns named 'Record'. Test Plan: existing tests Reviewers: dsagal Reviewed By: dsagal Differential Revision: https://phab.getgrist.com/D2913
295 lines
11 KiB
Python
295 lines
11 KiB
Python
import testsamples
|
|
import test_engine
|
|
from schema import RecalcWhen
|
|
|
|
class TestCompletion(test_engine.EngineTestCase):
|
|
user = {
|
|
'Name': 'Foo',
|
|
'UserID': 1,
|
|
'StudentInfo': ['Students', 1],
|
|
'LinkKey': {},
|
|
'Origin': None,
|
|
'Email': 'foo@example.com',
|
|
'Access': 'owners'
|
|
}
|
|
|
|
def setUp(self):
|
|
super(TestCompletion, self).setUp()
|
|
self.load_sample(testsamples.sample_students)
|
|
|
|
# To test different column types, we add some differently-typed columns to the sample.
|
|
self.add_column('Students', 'school', type='Ref:Schools')
|
|
self.add_column('Students', 'birthDate', type='Date')
|
|
self.add_column('Students', 'lastVisit', type='DateTime:America/New_York')
|
|
self.add_column('Schools', 'yearFounded', type='Int')
|
|
self.add_column('Schools', 'budget', type='Numeric')
|
|
self.add_column('Schools', 'lastModified',
|
|
type="DateTime:America/Los_Angeles", isFormula=False, formula="NOW()",
|
|
recalcWhen=RecalcWhen.MANUAL_UPDATES
|
|
)
|
|
self.add_column('Schools', 'lastModifier',
|
|
type="Text", isFormula=False, formula="foo@getgrist.com",
|
|
recalcWhen=RecalcWhen.MANUAL_UPDATES
|
|
)
|
|
|
|
def test_keyword(self):
|
|
self.assertEqual(self.engine.autocomplete("for", "Address", "city", self.user),
|
|
["for", "format("])
|
|
|
|
def test_grist(self):
|
|
self.assertEqual(self.engine.autocomplete("gri", "Address", "city", self.user),
|
|
["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),
|
|
["value"]
|
|
)
|
|
self.assertEqual(
|
|
self.engine.autocomplete("val", "Students", "schoolCities", self.user),
|
|
[]
|
|
)
|
|
self.assertEqual(
|
|
self.engine.autocomplete("val", "Students", "nonexistentColumn", self.user),
|
|
[]
|
|
)
|
|
self.assertEqual(self.engine.autocomplete("valu", "Schools", "lastModifier", self.user),
|
|
["value"])
|
|
# Should have same type as column.
|
|
self.assertGreaterEqual(
|
|
set(self.engine.autocomplete("value.", "Schools", "lastModifier", self.user)),
|
|
{'value.startswith(', 'value.replace(', 'value.title('}
|
|
)
|
|
self.assertGreaterEqual(
|
|
set(self.engine.autocomplete("value.", "Schools", "lastModified", self.user)),
|
|
{'value.month', 'value.strftime(', 'value.replace('}
|
|
)
|
|
self.assertGreaterEqual(
|
|
set(self.engine.autocomplete("value.m", "Schools", "lastModified", self.user)),
|
|
{'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),
|
|
["user"])
|
|
self.assertEqual(self.engine.autocomplete("use", "Students", "schoolCities", self.user),
|
|
[])
|
|
self.assertEqual(self.engine.autocomplete("use", "Students", "nonexistentColumn", self.user),
|
|
[])
|
|
self.assertEqual(self.engine.autocomplete("user", "Schools", "lastModifier", self.user),
|
|
["user"])
|
|
self.assertEqual(
|
|
self.engine.autocomplete("user.", "Schools", "lastModified", self.user),
|
|
[
|
|
'user.Access',
|
|
'user.Email',
|
|
'user.LinkKey',
|
|
'user.Name',
|
|
'user.Origin',
|
|
'user.StudentInfo',
|
|
'user.UserID'
|
|
]
|
|
)
|
|
# Should follow user attribute references and autocomplete those types.
|
|
self.assertEqual(
|
|
self.engine.autocomplete("user.StudentInfo.", "Schools", "lastModified", self.user),
|
|
[
|
|
'user.StudentInfo.birthDate',
|
|
'user.StudentInfo.firstName',
|
|
'user.StudentInfo.id',
|
|
'user.StudentInfo.lastName',
|
|
'user.StudentInfo.lastVisit',
|
|
'user.StudentInfo.school',
|
|
'user.StudentInfo.schoolCities',
|
|
'user.StudentInfo.schoolIds',
|
|
'user.StudentInfo.schoolName'
|
|
]
|
|
)
|
|
# Should not show user attribute completions if user doesn't have attribute.
|
|
user2 = {
|
|
'Name': 'Bar',
|
|
'Origin': None,
|
|
'Email': 'baro@example.com',
|
|
'LinkKey': {},
|
|
'UserID': 2,
|
|
'Access': 'owners'
|
|
}
|
|
self.assertEqual(
|
|
self.engine.autocomplete("user.", "Schools", "lastModified", user2),
|
|
[
|
|
'user.Access',
|
|
'user.Email',
|
|
'user.LinkKey',
|
|
'user.Name',
|
|
'user.Origin',
|
|
'user.UserID'
|
|
]
|
|
)
|
|
self.assertEqual(
|
|
self.engine.autocomplete("user.StudentInfo.", "Schools", "schoolCities", user2),
|
|
[]
|
|
)
|
|
|
|
def test_function(self):
|
|
self.assertEqual(self.engine.autocomplete("MEDI", "Address", "city", self.user),
|
|
[('MEDIAN', '(value, *more_values)', True)])
|
|
self.assertEqual(self.engine.autocomplete("ma", "Address", "city", self.user), [
|
|
('MAX', '(value, *more_values)', True),
|
|
('MAXA', '(value, *more_values)', True),
|
|
'map(',
|
|
'math',
|
|
'max(',
|
|
])
|
|
|
|
def test_member(self):
|
|
self.assertEqual(self.engine.autocomplete("datetime.tz", "Address", "city", self.user),
|
|
["datetime.tzinfo("])
|
|
|
|
def test_case_insensitive(self):
|
|
self.assertEqual(self.engine.autocomplete("medi", "Address", "city", self.user),
|
|
[('MEDIAN', '(value, *more_values)', True)])
|
|
self.assertEqual(self.engine.autocomplete("std", "Address", "city", self.user), [
|
|
('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),
|
|
["Students"])
|
|
|
|
# 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), [
|
|
('MAX', '(value, *more_values)', True),
|
|
('MAXA', '(value, *more_values)', True),
|
|
'Max',
|
|
'max(',
|
|
])
|
|
self.assertEqual(self.engine.autocomplete("MAX", "Address", "city", self.user), [
|
|
('MAX', '(value, *more_values)', True),
|
|
('MAXA', '(value, *more_values)', True),
|
|
])
|
|
|
|
|
|
def test_suggest_globals_and_tables(self):
|
|
# Should suggest globals and table names.
|
|
self.assertEqual(self.engine.autocomplete("ME", "Address", "city", self.user),
|
|
[('MEDIAN', '(value, *more_values)', True)])
|
|
self.assertEqual(self.engine.autocomplete("Ad", "Address", "city", self.user), ['Address'])
|
|
self.assertGreaterEqual(set(self.engine.autocomplete("S", "Address", "city", self.user)), {
|
|
'Schools',
|
|
'Students',
|
|
('SUM', '(value1, *more_values)', True),
|
|
('STDEV', '(value, *more_values)', True),
|
|
})
|
|
self.assertGreaterEqual(set(self.engine.autocomplete("s", "Address", "city", self.user)), {
|
|
'Schools',
|
|
'Students',
|
|
'sum(',
|
|
('SUM', '(value1, *more_values)', True),
|
|
('STDEV', '(value, *more_values)', True),
|
|
})
|
|
self.assertEqual(self.engine.autocomplete("Addr", "Schools", "budget", self.user), ['Address'])
|
|
|
|
def test_suggest_columns(self):
|
|
self.assertEqual(self.engine.autocomplete("$ci", "Address", "city", self.user),
|
|
["$city"])
|
|
self.assertEqual(self.engine.autocomplete("rec.i", "Address", "city", self.user),
|
|
["rec.id"])
|
|
self.assertEqual(len(self.engine.autocomplete("$", "Address", "city", self.user)),
|
|
2)
|
|
|
|
# A few more detailed examples.
|
|
self.assertEqual(self.engine.autocomplete("$", "Students", "school", self.user),
|
|
['$birthDate', '$firstName', '$id', '$lastName', '$lastVisit',
|
|
'$school', '$schoolCities', '$schoolIds', '$schoolName'])
|
|
self.assertEqual(self.engine.autocomplete("$fi", "Students", "birthDate", self.user),
|
|
['$firstName'])
|
|
self.assertEqual(self.engine.autocomplete("$school", "Students", "lastVisit", self.user),
|
|
['$school', '$schoolCities', '$schoolIds', '$schoolName'])
|
|
|
|
def test_suggest_lookup_methods(self):
|
|
# Should suggest lookup formulas for tables.
|
|
self.assertEqual(self.engine.autocomplete("Address.", "Students", "firstName", self.user), [
|
|
('Address.Record', '', True),
|
|
('Address.RecordSet', '', True),
|
|
'Address.all',
|
|
('Address.lookupOne', '(colName=<value>, ...)', True),
|
|
('Address.lookupRecords', '(colName=<value>, ...)', True),
|
|
])
|
|
|
|
self.assertEqual(
|
|
self.engine.autocomplete("Address.lookup", "Students", "lastName", self.user),
|
|
[
|
|
('Address.lookupOne', '(colName=<value>, ...)', True),
|
|
('Address.lookupRecords', '(colName=<value>, ...)', True),
|
|
]
|
|
)
|
|
|
|
self.assertEqual(
|
|
self.engine.autocomplete("address.look", "Students", "schoolName", self.user),
|
|
[
|
|
('Address.lookupOne', '(colName=<value>, ...)', True),
|
|
('Address.lookupRecords', '(colName=<value>, ...)', True),
|
|
]
|
|
)
|
|
|
|
def test_suggest_column_type_methods(self):
|
|
# Should treat columns as correct types.
|
|
self.assertGreaterEqual(
|
|
set(self.engine.autocomplete("$firstName.", "Students", "firstName", self.user)),
|
|
{'$firstName.startswith(', '$firstName.replace(', '$firstName.title('}
|
|
)
|
|
self.assertGreaterEqual(
|
|
set(self.engine.autocomplete("$birthDate.", "Students", "lastName", self.user)),
|
|
{'$birthDate.month', '$birthDate.strftime(', '$birthDate.replace('}
|
|
)
|
|
self.assertGreaterEqual(
|
|
set(self.engine.autocomplete("$lastVisit.m", "Students", "firstName", self.user)),
|
|
{'$lastVisit.month', '$lastVisit.minute'}
|
|
)
|
|
self.assertGreaterEqual(
|
|
set(self.engine.autocomplete("$school.", "Students", "firstName", self.user)),
|
|
{'$school.address', '$school.name', '$school.yearFounded', '$school.budget'}
|
|
)
|
|
self.assertEqual(self.engine.autocomplete("$school.year", "Students", "lastName", self.user),
|
|
['$school.yearFounded'])
|
|
self.assertGreaterEqual(
|
|
set(self.engine.autocomplete("$yearFounded.", "Schools", "budget", self.user)),
|
|
{
|
|
'$yearFounded.denominator', # Only integers have this
|
|
'$yearFounded.bit_length(', # and this
|
|
'$yearFounded.real'
|
|
}
|
|
)
|
|
self.assertGreaterEqual(
|
|
set(self.engine.autocomplete("$budget.", "Schools", "budget", self.user)),
|
|
{'$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),
|
|
['$school.name.startswith(', '$school.name.strip(']
|
|
)
|
|
self.assertGreaterEqual(
|
|
set(self.engine.autocomplete("$school.yearFounded.","Students", "firstName", self.user)),
|
|
{
|
|
'$school.yearFounded.denominator',
|
|
'$school.yearFounded.bit_length(',
|
|
'$school.yearFounded.real'
|
|
}
|
|
)
|
|
|
|
self.assertEqual(
|
|
self.engine.autocomplete("$school.address.", "Students", "lastName", self.user),
|
|
['$school.address.city', '$school.address.id']
|
|
)
|
|
self.assertEqual(
|
|
self.engine.autocomplete("$school.address.city.st", "Students", "lastName", self.user),
|
|
['$school.address.city.startswith(', '$school.address.city.strip(']
|
|
)
|