Fixed #68: Implement SheerkaQL
Fixed #70: SheerkaFilterManager : Pipe functions Fixed #71: SheerkaFilterManager : filter_objects Fixed #75: SheerkaMemory: Enhance memory() to use the filtering capabilities Fixed #76: SheerkaEvaluateConcept: Concepts that modify the state of the system must not be evaluated during question
This commit is contained in:
@@ -0,0 +1,297 @@
|
||||
import pytest
|
||||
|
||||
from sheerkaql.SheerkaQueryLangage import SheerkaQueryLanguage
|
||||
from sheerkaql.lexer import Lexer
|
||||
from sheerkaql.parser import Parser
|
||||
|
||||
|
||||
class TestSheerkaQueryLanguageParser:
|
||||
def test_hello(self):
|
||||
SheerkaQueryLanguage().compile('hello')
|
||||
with pytest.raises(SyntaxError) as ex:
|
||||
SheerkaQueryLanguage().compile('hello there')
|
||||
|
||||
def test_i_can_parse_with_slash(self):
|
||||
SheerkaQueryLanguage().compile('hello/part1')
|
||||
SheerkaQueryLanguage().compile('hello/part1/part2/part3')
|
||||
SheerkaQueryLanguage().compile('hello/part1 / part2 / part3')
|
||||
with pytest.raises(SyntaxError):
|
||||
SheerkaQueryLanguage().compile('hello/part1/part3 part4/part5')
|
||||
|
||||
def test_i_can_parse_with_dot(self):
|
||||
SheerkaQueryLanguage().compile('hello.part1')
|
||||
SheerkaQueryLanguage().compile('hello.part1.part2.part3')
|
||||
SheerkaQueryLanguage().compile('hello.part1 . part2 . part3')
|
||||
with pytest.raises(SyntaxError):
|
||||
SheerkaQueryLanguage().compile('hello.part1.part3 part4.part5')
|
||||
|
||||
def test_i_can_parse_simple_where_conditions(self):
|
||||
SheerkaQueryLanguage().compile('hello[wheRe]/hello[asdf]')
|
||||
SheerkaQueryLanguage().compile('hello/hello[asdf]/asdf/wef')
|
||||
SheerkaQueryLanguage().compile('hello/hello/wewe[asdf]/wef/waef/awef/weaf')
|
||||
SheerkaQueryLanguage().compile('hello.hello[ asdf ] . wewe. wef[asdf] .waef .awef[asdf].weaf')
|
||||
SheerkaQueryLanguage().compile('hello["foo"]')
|
||||
SheerkaQueryLanguage().compile('hello[123]')
|
||||
SheerkaQueryLanguage().compile('hello[123.234]')
|
||||
with pytest.raises(SyntaxError):
|
||||
SheerkaQueryLanguage().compile('hello/aef[asdf] hello[adsf]')
|
||||
|
||||
def test_i_can_parse_where_conditions_with_comparisons(self):
|
||||
SheerkaQueryLanguage().compile('hello[1 == 1]')
|
||||
SheerkaQueryLanguage().compile('hello[1 != 1]')
|
||||
SheerkaQueryLanguage().compile('hello[1 < 1]')
|
||||
SheerkaQueryLanguage().compile('hello[1 <= 1]')
|
||||
SheerkaQueryLanguage().compile('hello[1 > 1]')
|
||||
SheerkaQueryLanguage().compile('hello[1 >= 1]')
|
||||
|
||||
def test_i_can_parse_where_conditions_with_logical_operations(self):
|
||||
SheerkaQueryLanguage().compile('hello[a and b]')
|
||||
SheerkaQueryLanguage().compile('hello[a or b]')
|
||||
SheerkaQueryLanguage().compile('hello[not a or b]')
|
||||
SheerkaQueryLanguage().compile('hello[a or not b]')
|
||||
SheerkaQueryLanguage().compile('hello[not a and b]')
|
||||
SheerkaQueryLanguage().compile('hello[a and not b]')
|
||||
SheerkaQueryLanguage().compile('hello[not a or not b]')
|
||||
SheerkaQueryLanguage().compile('hello[not a and not b]')
|
||||
|
||||
def test_i_can_parse_where_conditions_with_logical_operations_and_parenthesis(self):
|
||||
SheerkaQueryLanguage().compile('hello[((a and b) and not (a or b) or not (a and b)) and not (not a or b)]')
|
||||
|
||||
def test_i_can_parse_where_conditions_with_arithmetic_operations(self):
|
||||
SheerkaQueryLanguage().compile('hello[a + b]')
|
||||
SheerkaQueryLanguage().compile('hello[a - b]')
|
||||
SheerkaQueryLanguage().compile('hello[a * b]')
|
||||
SheerkaQueryLanguage().compile('hello[a / b]')
|
||||
SheerkaQueryLanguage().compile('hello[(a + b) / (a - b)]')
|
||||
SheerkaQueryLanguage().compile('hello[-a]')
|
||||
SheerkaQueryLanguage().compile('hello[a + b * c / e]')
|
||||
|
||||
def test_i_can_parse_nested_where_conditions(self):
|
||||
SheerkaQueryLanguage().compile('hello[a]')
|
||||
SheerkaQueryLanguage().compile("hello[a[0]['hello']]")
|
||||
SheerkaQueryLanguage().compile("hello[a[0][\"hello\"]]")
|
||||
|
||||
def test_i_can_parse_where_conditions_with_function_call(self):
|
||||
SheerkaQueryLanguage().compile("hello[a[0]['hello']()]")
|
||||
SheerkaQueryLanguage().compile("hello[a[0]['hello'](0)]")
|
||||
SheerkaQueryLanguage().compile("hello[a[0]['hello']('asdf')]")
|
||||
SheerkaQueryLanguage().compile("hello[a[0]['hello'](asdf)]")
|
||||
SheerkaQueryLanguage().compile("hello[a[0]['hello'](0, 'asdf', asdf)()()(1,2)]")
|
||||
SheerkaQueryLanguage().compile('hello[f(1)]')
|
||||
SheerkaQueryLanguage().compile('hello[f(1,2,3)]')
|
||||
SheerkaQueryLanguage().compile('hello[f(a,b,c)]')
|
||||
SheerkaQueryLanguage().compile('hello[f(a(),b(),c())]')
|
||||
SheerkaQueryLanguage().compile('hello[f(a[a],b[b],c[c])]')
|
||||
|
||||
def test_i_can_parse_where_conditions_with_attributes_parsing(self):
|
||||
SheerkaQueryLanguage().compile('hello[foo.bar.baz]')
|
||||
SheerkaQueryLanguage().compile('hello[foo[12].bar().baz]')
|
||||
|
||||
def test_i_can_parse_where_conditions_with_flwr(self):
|
||||
SheerkaQueryLanguage().compile('hello[f(1,<asdf>,{for x in <asdf> return x})]')
|
||||
|
||||
def test_i_can_parse_where_conditions_with_quantified_expressions(self):
|
||||
SheerkaQueryLanguage().compile('hello[every x in <asdf> satisfies (x)]')
|
||||
with pytest.raises(SyntaxError):
|
||||
SheerkaQueryLanguage().compile('hello[every x in <asdf> statisfies (x)]')
|
||||
with pytest.raises(SyntaxError):
|
||||
SheerkaQueryLanguage().compile('hello[every x in <asdf> statisfies x]')
|
||||
SheerkaQueryLanguage().compile('hello[some x in <asdf> satisfies (x)]')
|
||||
SheerkaQueryLanguage().compile('hello[some x in <self/asdf> satisfies (x)]')
|
||||
SheerkaQueryLanguage().compile('hello[some x in {for x in <asdf> return x} satisfies (x)]')
|
||||
SheerkaQueryLanguage().compile('hello[some x in {for x in <asdf> return x} satisfies (x == y)]')
|
||||
SheerkaQueryLanguage().compile('hello[some x in {for x in <asdf> return x} satisfies (x and not y(1,2))]')
|
||||
|
||||
def test_i_can_parse_where_conditions_with_set_comparisons(self):
|
||||
SheerkaQueryLanguage().compile('hello[a in <qs>]')
|
||||
SheerkaQueryLanguage().compile('hello[a not in <qs>]')
|
||||
SheerkaQueryLanguage().compile('hello[not a in <qs>]')
|
||||
SheerkaQueryLanguage().compile('hello[<a> subset <qs>]')
|
||||
SheerkaQueryLanguage().compile('hello[<a> superset <qq>]')
|
||||
SheerkaQueryLanguage().compile('hello[<a> proper subset <aq>]')
|
||||
SheerkaQueryLanguage().compile('hello[<a> proper superset <aq>]')
|
||||
SheerkaQueryLanguage().compile('hello[<a> is <qs>]')
|
||||
SheerkaQueryLanguage().compile('hello[<a> is not <qs>]')
|
||||
|
||||
def test_i_can_parse_operations_on_sets(self):
|
||||
SheerkaQueryLanguage().compile('asdf - asdf')
|
||||
SheerkaQueryLanguage().compile('asdf & asdf')
|
||||
SheerkaQueryLanguage().compile('asdf | asdf')
|
||||
SheerkaQueryLanguage().compile('(asdf | asdf) & asdf - (asdf & asdf) - (asdf & (afsd | asdf))')
|
||||
SheerkaQueryLanguage().compile('asdf/asdf - asdf/asd[erw]')
|
||||
|
||||
def test_i_can_parse_flwr_expression(self):
|
||||
SheerkaQueryLanguage().compile('for x in y return x')
|
||||
SheerkaQueryLanguage().compile('for x in <asfd> return x')
|
||||
SheerkaQueryLanguage().compile('for x in <asfd>, y in <adsf> return x')
|
||||
SheerkaQueryLanguage().compile('for x in {for x in <asdf> return x} return x')
|
||||
SheerkaQueryLanguage().compile('for x in <asfd> where x == y return x')
|
||||
SheerkaQueryLanguage().compile('for x in <asfd> let y = <x/asdf> return x')
|
||||
SheerkaQueryLanguage().compile('for x in <asfd> let y = {for x in <asdf> return x} return x')
|
||||
SheerkaQueryLanguage().compile('for x in <asfd> let y = <x/asdf>, x = <adf> return x')
|
||||
SheerkaQueryLanguage().compile('for x in <asfd> let y = <x/asdf> let x = <adf> return x')
|
||||
SheerkaQueryLanguage().compile('for x in <asfd>, z in <asdf> let y = <x/asdf> let x = <adf> return x')
|
||||
SheerkaQueryLanguage().compile('''for x in <asfd>, z in <asdf>
|
||||
let y = <x/asdf>
|
||||
let x = <adf>
|
||||
where every x in <y> satisfies (q)
|
||||
return x''')
|
||||
SheerkaQueryLanguage().compile('''for x in <asfd>, z in <asdf>
|
||||
let y = <x/asdf>
|
||||
let x = <adf>
|
||||
where every x in <y> satisfies (q)
|
||||
return x,y,z''')
|
||||
SheerkaQueryLanguage().compile('''for x in <asfd>, z in <asdf>
|
||||
let y = <x/asdf>
|
||||
let x = <adf>
|
||||
where every x in <y> satisfies (q)
|
||||
return x,y.sdf.asd,z''')
|
||||
SheerkaQueryLanguage().compile('''for x in <asfd>, z in <asdf>
|
||||
let y = <x/asdf>
|
||||
let x = <adf>
|
||||
where every x in <y> satisfies (q)
|
||||
return x,y.sdf.asd,z()()()[asdf][asfd](1,2,3)''')
|
||||
SheerkaQueryLanguage().compile('''for x in <asfd>, z in <asdf>
|
||||
let y = <x/asdf>
|
||||
let x = <adf>
|
||||
where every x in <y> satisfies (q)
|
||||
return 'asdf':asdf''')
|
||||
SheerkaQueryLanguage().compile('''for x in <asfd>, z in <asdf>
|
||||
let y = <x/asdf>
|
||||
let x = <adf>
|
||||
where every x in <y> satisfies (q)
|
||||
return 'asdf':asdf, "hello":"hello World!"''')
|
||||
SheerkaQueryLanguage().compile('''for x in <asfd>, z in <asdf>
|
||||
let y = <x/asdf>
|
||||
let x = <adf>
|
||||
where every x in <y> satisfies (q == z and (<y> is not <z>))
|
||||
return 'asdf':asdf, "one":1, "2.0":2.0''')
|
||||
SheerkaQueryLanguage().compile('''for x in <asfd>, z in <asdf>, y in <asdf/asdf>
|
||||
let y = <x/asdf>
|
||||
let x = <adf>
|
||||
where every x in <y> satisfies (q == z and (<y> is not <z>))
|
||||
return 'asdf':asdf, "one":1, "2.0":2.0''')
|
||||
SheerkaQueryLanguage().compile('''for x in <asfd>, z in <asdf>, y in <asdf/asdf>
|
||||
let y = <x/asdf>, y1 = <Afd>, y2 = <asdf>, y3 = <asdf>
|
||||
let x = <adf>
|
||||
where every x in <y> satisfies (q == z and (<y> is not <z>))
|
||||
return 'asdf':asdf, "one":1, "2.0":2.0''')
|
||||
|
||||
def test_i_can_parse_flwr_with_attribute_value(self):
|
||||
SheerkaQueryLanguage().compile('''for x in <asfd>, z in <asdf>, y in sdaf.asdf(asdf, asdf)[1]
|
||||
let y = <x/asdf>, y1 = <Afd>, y2 = <asdf>, y3 = <asdf>
|
||||
let x = <adf>
|
||||
where every x in <y> satisfies (q == z and (<y> is not <z>))
|
||||
return 'asdf':asdf, "one":1, "2.0":2.0''')
|
||||
SheerkaQueryLanguage().compile('''for x in <asfd>, z in <asdf>, y in sdaf.asdf(asdf, asdf)[1]
|
||||
let y = <x/asdf>, y1 = <Afd>, y2 = <asdf>, y3 = <asdf>
|
||||
let x = <adf>
|
||||
let q = sadf.asdf().asfd[1](1,2,3)
|
||||
where every x in <y> satisfies (q == z and (<y> is not <z>))
|
||||
return 'asdf':asdf, "one":1, "2.0":2.0''')
|
||||
|
||||
def test_flwr_orderby(self):
|
||||
SheerkaQueryLanguage().compile('for x in <asdf> order by "adsf" desc return "adsf":x')
|
||||
SheerkaQueryLanguage().compile('''for x in <asfd>, z in <asdf>, y in sdaf.asdf(asdf, asdf)[1]
|
||||
let y = <x/asdf>, y1 = <Afd>, y2 = <asdf>, y3 = <asdf>
|
||||
let x = <adf>
|
||||
where every x in <y> satisfies (q == z and (<y> is not <z>))
|
||||
order by "asdf" desc
|
||||
return 'asdf':asdf, "one":1, "2.0":2.0''')
|
||||
SheerkaQueryLanguage().compile('for x in <asdf> order by 0 asc return x')
|
||||
SheerkaQueryLanguage().compile('''for x in <asfd>, z in <asdf>, y in sdaf.asdf(asdf, asdf)[1]
|
||||
let y = <x/asdf>, y1 = <Afd>, y2 = <asdf>, y3 = <asdf>
|
||||
let x = <adf>
|
||||
where every x in <y> satisfies (q == z and (<y> is not <z>))
|
||||
order by 1 asc
|
||||
return asdf, 1, 2.0''')
|
||||
|
||||
def test_flwr_function_noargs(self):
|
||||
SheerkaQueryLanguage().compile('''
|
||||
for x in <asdf>
|
||||
let f = function() { for y in <asdf> return y }
|
||||
return f
|
||||
''')
|
||||
|
||||
def test_flwr_function_args(self):
|
||||
SheerkaQueryLanguage().compile('''
|
||||
for x in <asdf>
|
||||
let f = function(q) { for y in q return y }
|
||||
return f
|
||||
''')
|
||||
|
||||
def test_if(self):
|
||||
SheerkaQueryLanguage().compile('''
|
||||
for x in <asdf> return if (0) then 1 else 0
|
||||
''')
|
||||
|
||||
def test_reduce(self):
|
||||
SheerkaQueryLanguage().compile('''
|
||||
for x in <asdf>
|
||||
collect x.tree as x.attr with function(prev, next) {
|
||||
if prev == None then next else prev.combine(next)
|
||||
}
|
||||
''')
|
||||
|
||||
def test_in_list1(self):
|
||||
SheerkaQueryLanguage().compile("hello['foo' in ['foo','bar']]")
|
||||
|
||||
def test_in_list2(self):
|
||||
SheerkaQueryLanguage().compile("hello['baz' in ['foo','bar']]")
|
||||
|
||||
def test_not_in_list1(self):
|
||||
SheerkaQueryLanguage().compile("hello['foo' not in ['foo','bar']]")
|
||||
|
||||
def test_not_in_list2(self):
|
||||
SheerkaQueryLanguage().compile("hello['baz' not in ['foo','bar']]")
|
||||
|
||||
def test_in_list3(self):
|
||||
result = SheerkaQueryLanguage().execute("res[test_elt in ['foo','bar']]",
|
||||
{'res': True, 'test_elt': 'foo'})
|
||||
assert bool(result)
|
||||
|
||||
def test_in_list4(self):
|
||||
result = SheerkaQueryLanguage().execute("res[test_elt in ['foo','bar']]",
|
||||
{'res': True, 'test_elt': 'baz'})
|
||||
|
||||
assert not bool(result)
|
||||
|
||||
def test_not_in_list4(self):
|
||||
result = SheerkaQueryLanguage().execute("res[test_elt not in ['foo','bar']]",
|
||||
{'res': True, 'test_elt': 'baz'})
|
||||
assert bool(result)
|
||||
|
||||
def test_not_in_list5(self):
|
||||
result = SheerkaQueryLanguage().execute("res[test_elt not in ['foo','bar']]",
|
||||
{'res': True, 'test_elt': 'foo'})
|
||||
assert not bool(result)
|
||||
|
||||
@pytest.mark.parametrize("text, expected", [
|
||||
("hello", {"hello"}),
|
||||
("hello.foo.bar", {"hello"}),
|
||||
("hello/foo/bar", {"hello"}),
|
||||
("hello[foo.bar.baz]", {"hello", "foo"}),
|
||||
("hello[foo()]", {"hello", "foo"}),
|
||||
("hello[foo(bar)]", {"hello", "foo", "bar"}),
|
||||
("hello[foo(1, bar.baz)]", {"hello", "foo", "bar"}),
|
||||
("hello[foo[bar]]", {"hello", "foo", "bar"}),
|
||||
("hello[foo > bar]", {"hello", "foo", "bar"}),
|
||||
("hello[foo + bar]", {"hello", "foo", "bar"}),
|
||||
("hello[[a,b,c]]", {"hello", "a", "b", "c"}),
|
||||
("hello[{a:b}]", {"hello", "a", "b"}),
|
||||
])
|
||||
def test_i_can_get_names(self, text, expected):
|
||||
parser = Parser()
|
||||
parser.parse(bytes(text, 'utf-8').decode('unicode_escape'), lexer=Lexer())
|
||||
assert parser.names == expected
|
||||
|
||||
@pytest.mark.parametrize("text", [
|
||||
"sheerka.method",
|
||||
"sheerka/method",
|
||||
"hello[sheerka.method]",
|
||||
"hello[sheerka.method.xx]",
|
||||
])
|
||||
def test_i_can_get_sheerka_methods(self, text):
|
||||
parser = Parser()
|
||||
parser.parse(bytes(text, 'utf-8').decode('unicode_escape'), lexer=Lexer())
|
||||
assert parser.sheerka_names == {"method"}
|
||||
Reference in New Issue
Block a user