Skip to content

Commit 649c0fd

Browse files
committed
Refactoring and more tests
1 parent 0fa713e commit 649c0fd

File tree

6 files changed

+151
-3
lines changed

6 files changed

+151
-3
lines changed

preql/autocomplete.py

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from lark import Token, UnexpectedCharacters, UnexpectedToken, Tree
44

55
from .exceptions import ReturnSignal, pql_NameNotFound, PreqlError
6+
from .loggers import ac_log
67
from . import pql_ast as ast
78
from . import pql_objects as objects
89
from .utils import bfs

preql/loggers.py

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
from logging import getLogger, Formatter, StreamHandler, basicConfig
2+
from logging import DEBUG, INFO, WARN, ERROR, CRITICAL
3+
4+
basicConfig(level=INFO, format="(%(levelname)s) %(name)s -- %(message)s")
5+
# )#datefmt='%m-%d %H:%M')
6+
7+
sh = StreamHandler()
8+
sh.setFormatter(Formatter('%(message)s'))
9+
10+
def make_logger(name, level):
11+
logger = getLogger(name)
12+
logger.propagate = False
13+
logger.setLevel(level)
14+
logger.addHandler(sh)
15+
return logger
16+
17+
18+
19+
sql_log = make_logger('sql_output', DEBUG)
20+
ac_log = make_logger('autocomplete', CRITICAL)
21+
repl_log = make_logger('repl', INFO)
22+
test_log = make_logger('tests', ERROR)

tests/__main__.py

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
logging.basicConfig(level=logging.INFO)
44

55
from .test_basic import *
6+
from .test_autocomplete import AutocompleteTests
67

78

89
if __name__ == '__main__':

tests/common.py

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from unittest import TestCase, skip
2+
from preql import sql, settings
3+
4+
from preql import Preql
5+
6+
SQLITE_URI = 'sqlite://:memory:'
7+
POSTGRES_URI = 'postgres://postgres:qweqwe123@localhost/postgres'
8+
9+
class PreqlTests(TestCase):
10+
def Preql(self):
11+
settings.optimize = self.optimized
12+
preql = Preql(self.uri)
13+
self.preql = preql
14+
return preql
15+
16+
def setUp(self):
17+
self.preql = None
18+
19+
def tearDown(self):
20+
if self.preql:
21+
self.preql.engine.rollback()

tests/test_autocomplete.py

+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import re
2+
import time
3+
import logging
4+
5+
from preql import Preql
6+
from preql.autocomplete import autocomplete
7+
from preql.loggers import test_log
8+
9+
from .common import PreqlTests, SQLITE_URI, POSTGRES_URI
10+
11+
class AutocompleteTests(PreqlTests):
12+
uri = SQLITE_URI
13+
optimized = True
14+
15+
def test_basic(self):
16+
p = self.Preql()
17+
state = p.interp.state
18+
19+
assert "value" in autocomplete(state, "func d(){ [1]{")
20+
assert "value" in autocomplete(state, "func d(){ [1][")
21+
assert "value" not in autocomplete(state, "func d(){ [1]")
22+
23+
res = autocomplete(state, """
24+
func x(param1) {
25+
hello = "b"
26+
""")
27+
assert "hello" in res, res.keys()
28+
29+
res = autocomplete(state, """
30+
func x(param1) {
31+
hello = "b
32+
""")
33+
34+
res = autocomplete(state, """
35+
func x(param1) {
36+
hello = [1] {value, value+2}
37+
""")
38+
assert "hello" in res, res.keys()
39+
40+
def test_progressive(self):
41+
p = self.Preql()
42+
state = p.interp.state
43+
44+
s0 = """
45+
func hello() = 0
46+
47+
a = <<<hello>>>
48+
"""
49+
progressive_test(state, s0)
50+
progressive_test(state, s0, True)
51+
52+
s1 = """
53+
func get_users(logins) {
54+
const table matched_logins = <<<leftjoin>>>(l:logins.value, u:User.login)
55+
56+
existing_users = <<<matched_logins>>>[<<<u>>>!=null] {<<<u>>>.id}
57+
new_users = new[] User(login: <<<matched_logins>>>[<<<u>>>==null] {<<<l>>>.value})
58+
59+
return <<<existing_users>>> + <<<new_users>>>
60+
}
61+
62+
hello = <<<get_users>>>([1,2,3])
63+
do_whatever = <<<hello>>>
64+
65+
"""
66+
progressive_test(state, s1*2)
67+
progressive_test(state, s1, True)
68+
69+
70+
71+
72+
def _parse_autocomplete_requirements(s):
73+
matches = {}
74+
offset = 0
75+
def g(m):
76+
nonlocal offset
77+
start = m.start() + offset
78+
x ,= m.groups()
79+
matches[start] = x
80+
offset -= 6
81+
return x
82+
83+
new_s = re.sub("<<<(\w+)>>>", g, s)
84+
for k, v in matches.items():
85+
assert new_s[k:k+len(v)] == v, (k, v)
86+
return new_s, matches
87+
88+
89+
def progressive_test(state, s, test_partial=False):
90+
total = 0
91+
start = time.time()
92+
93+
s,d = _parse_autocomplete_requirements(s)
94+
for i in range(1, len(s)):
95+
ps = s[:i]
96+
if i in d or test_partial:
97+
names = autocomplete(state, ps)
98+
total += 1
99+
if i in d:
100+
assert d[i] in names, (i, d[i])
101+
102+
duration = time.time() - start
103+
test_log.info(f"Total {total} autocompletions in {duration:.2f} seconds, or {1000*duration/total:.2f} ms per autocomplete")

tests/test_basic.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
from preql import sql, settings
1111
from preql.pql_types import T
1212

13-
SQLITE_URI = 'sqlite://:memory:'
14-
POSTGRES_URI = 'postgres://postgres:qweqwe123@localhost/postgres'
13+
from .common import PreqlTests, SQLITE_URI, POSTGRES_URI
14+
1515

1616

1717
def is_eq(a, b):
@@ -24,7 +24,7 @@ def is_eq(a, b):
2424
("Unoptimized_Lt", SQLITE_URI, False),
2525
("Unoptimized_Pg", POSTGRES_URI, False),
2626
])
27-
class BasicTests(TestCase):
27+
class BasicTests(PreqlTests):
2828
def Preql(self):
2929
settings.optimize = self.optimized
3030
preql = Preql(self.uri)

0 commit comments

Comments
 (0)