aboutsummaryrefslogtreecommitdiffstats
path: root/test/parsing
diff options
context:
space:
mode:
authorMatthias Baumgartner <dev@igsor.net>2023-01-13 09:49:10 +0100
committerMatthias Baumgartner <dev@igsor.net>2023-01-13 09:49:10 +0100
commit9c366758665d9cfee7796ee45a8167a5412ae9ae (patch)
treeb42e0a1fd4b1bd59fc31fad6267b83c2dc9a3a3b /test/parsing
parent8f2f697f7ed52b7e1c7a17411b2de526b6490691 (diff)
downloadtagit-9c366758665d9cfee7796ee45a8167a5412ae9ae.tar.gz
tagit-9c366758665d9cfee7796ee45a8167a5412ae9ae.tar.bz2
tagit-9c366758665d9cfee7796ee45a8167a5412ae9ae.zip
filter early port, parsing adaptions
Diffstat (limited to 'test/parsing')
-rw-r--r--test/parsing/test_filter.py751
-rw-r--r--test/parsing/test_search.py707
2 files changed, 751 insertions, 707 deletions
diff --git a/test/parsing/test_filter.py b/test/parsing/test_filter.py
new file mode 100644
index 0000000..c01c1bf
--- /dev/null
+++ b/test/parsing/test_filter.py
@@ -0,0 +1,751 @@
+"""
+
+Part of the tagit test suite.
+A copy of the license is provided with the project.
+Author: Matthias Baumgartner, 2022
+"""
+# standard imports
+import unittest
+from datetime import datetime
+
+# external imports
+from pyparsing import ParseException
+
+# tagit imports
+from tagit.utils import bsfs, errors, ns
+from tagit.utils.bsfs import ast
+
+# objects to test
+from tagit.parsing.filter import Filter
+
+
+## code ##
+
+class TestFilterRange(unittest.TestCase):
+ longMessage = True
+
+ def setUp(self):
+ #predicates.expose('mime', TestScope('attribute', 'mime'), 'Categorical')
+ #predicates.expose('iso', TestScope('attribute', 'iso'), 'Continuous', 'Categorical')
+ #predicates.expose('time', TestScope('generic', 't_image_create_loc'), 'TimeRange', 'Datetime')
+ #predicates.expose('tag', TestScope('generic', 'tag'), 'Categorical')
+
+ #predicates.expose('mime', TestScope('attribute', 'mime'), 'Categorical')
+ #predicates.expose('rank', TestScope('attribute', 'rank'), 'Continuous')
+ #predicates.expose('iso', TestScope('attribute', 'iso'), 'Continuous', 'Categorical')
+ #predicates.expose('time', TestScope('generic', 't_image_create_loc'), 'TimeRange', 'Datetime')
+ #predicates.expose('tag', TestScope('generic', 'tag'), 'Categorical')
+
+
+ self.schema = bsfs.schema.from_string('''
+ # common external prefixes
+ prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
+ prefix xsd: <http://www.w3.org/2001/XMLSchema#>
+
+ # common bsfs prefixes
+ prefix bsfs: <http://bsfs.ai/schema/>
+ prefix bse: <http://bsfs.ai/schema/Entity#>
+
+ # nodes
+ bsfs:Entity rdfs:subClassOf bsfs:Node .
+ bsfs:Tag rdfs:subClassOf bsfs:Node .
+
+ # literals
+ bsfs:Time rdfs:subClassOf bsfs:Literal .
+ xsd:string rdfs:subClassOf bsfs:Literal .
+ bsfs:Number rdfs:subClassOf bsfs:Literal .
+ xsd:integer rdfs:subClassOf bsfs:Number .
+
+ # predicates
+ bse:mime rdfs:subClassOf bsfs:Predicate ;
+ rdfs:domain bsfs:Entity ;
+ rdfs:range xsd:string ;
+ bsfs:unique "true"^^xsd:boolean .
+
+ bse:iso rdfs:subClassOf bsfs:Predicate ;
+ rdfs:domain bsfs:Entity ;
+ rdfs:range xsd:integer ;
+ bsfs:unique "true"^^xsd:boolean .
+
+ bse:time rdfs:subClassOf bsfs:Predicate ;
+ rdfs:domain bsfs:Entity ;
+ rdfs:range bsfs:Time;
+ bsfs:unique "true"^^xsd:boolean .
+
+ bse:tag rdfs:subClassOf bsfs:Predicate ;
+ rdfs:domain bsfs:Entity ;
+ rdfs:range bsfs:Tag ;
+ bsfs:unique "false"^^xsd:boolean .
+
+ bse:rank rdfs:subClassOf bsfs:Predicate ;
+ rdfs:domain bsfs:Entity ;
+ rdfs:range xsd:integer ;
+ bsfs:unique "false"^^xsd:boolean .
+
+ ''')
+ self.parse = Filter(self.schema)
+
+ def _test_number(self, query, target):
+ predicate, condition = target
+ result = self.parse(query)
+ target = ast.filter.And(ast.filter.Any(predicate, condition))
+ self.assertEqual(result, target, msg="in query '{}'".format(query))
+
+ def test_larger_than(self):
+ # larger than A (inclusive)
+ for editable in [
+ # range
+ "{predicate} in [{num}:]", "{predicate} in [{num}:[", "{predicate} in [{num}:)",
+ "{predicate} : [{num}:]", "{predicate} : [{num}:[", "{predicate} : [{num}:)",
+ "{predicate} = [{num}:]", "{predicate} = [{num}:[", "{predicate} = [{num}:)",
+ ]:
+ # positive
+ self._test_number(editable.format(num=1.23, predicate='iso'),
+ (ns.bse.iso, ast.filter.GreaterThan(1.23, False)))
+ # negative
+ self._test_number(editable.format(num=-1.23, predicate='iso'),
+ (ns.bse.iso, ast.filter.GreaterThan(-1.23, False)))
+
+ for editable in [
+ # range
+ "{predicate} in [{num}-]", "{predicate} in [{num}-[", "{predicate} in [{num}-)",
+ "{predicate} : [{num}-]", "{predicate} : [{num}-[", "{predicate} : [{num}-)",
+ "{predicate} = [{num}-]", "{predicate} = [{num}-[", "{predicate} = [{num}-)",
+ # equation
+ "{predicate} >= {num}", "{num} <= {predicate}",
+ ]:
+ # positive
+ self._test_number(editable.format(num=1.23, predicate='iso'),
+ (ns.bse.iso, ast.filter.GreaterThan(1.23, False)))
+ # negative
+ self._test_number(editable.format(num=-1.23, predicate='iso'),
+ (ns.bse.iso, ast.filter.GreaterThan(-1.23, False)))
+ # FIXME: date
+ #self._test_number(editable.format(predicate='time', num="30.04.2012, 13:18"),
+ # ('time', ast.Datetime(datetime(2012, 4, 30, 13, 18), datetime.max, True, False)))
+
+ # larger than A (exclusive)
+ for editable in [
+ # range / bracket
+ "{predicate} in ]{num}:]", "{predicate} in ]{num}:[", "{predicate} in ]{num}:)",
+ "{predicate} : ]{num}:]", "{predicate} : ]{num}:[", "{predicate} : ]{num}:)",
+ "{predicate} = ]{num}:]", "{predicate} = ]{num}:[", "{predicate} = ]{num}:)",
+ # range / parenthesis
+ "{predicate} in ({num}:]", "{predicate} in ({num}:[", "{predicate} in ({num}:)",
+ "{predicate} : ({num}:]", "{predicate} : ({num}:[", "{predicate} : ({num}:)",
+ "{predicate} = ({num}:]", "{predicate} = ({num}:[", "{predicate} = ({num}:)",
+ ]:
+ # positive
+ self._test_number(editable.format(num=1.23, predicate='iso'),
+ (ns.bse.iso, ast.filter.GreaterThan(1.23, True)))
+ # negative
+ self._test_number(editable.format(num=-1.23, predicate='iso'),
+ (ns.bse.iso, ast.filter.GreaterThan(-1.23, True)))
+
+ for editable in [
+ # range / bracket
+ "{predicate} in ]{num}-]", "{predicate} in ]{num}-[", "{predicate} in ]{num}-)",
+ "{predicate} : ]{num}-]", "{predicate} : ]{num}-[", "{predicate} : ]{num}-)",
+ "{predicate} = ]{num}-]", "{predicate} = ]{num}-[", "{predicate} = ]{num}-)",
+ # range / parenthesis
+ "{predicate} in ({num}-]", "{predicate} in ({num}-[", "{predicate} in ({num}-)",
+ "{predicate} : ({num}-]", "{predicate} : ({num}-[", "{predicate} : ({num}-)",
+ "{predicate} = ({num}-]", "{predicate} = ({num}-[", "{predicate} = ({num}-)",
+ # equation
+ "{predicate} > {num}", "{num} < {predicate}",
+ ]:
+ # positive
+ self._test_number(editable.format(num=1.23, predicate='iso'),
+ (ns.bse.iso, ast.filter.GreaterThan(1.23, True)))
+ # negative
+ self._test_number(editable.format(num=-1.23, predicate='iso'),
+ (ns.bse.iso, ast.filter.GreaterThan(-1.23, True)))
+ # FIXME: date
+ #self._test_number(editable.format(predicate='time', num="30.04.2012, 13:18"),
+ # ('time', ast.Datetime(datetime(2012, 4, 30, 13, 19), datetime.max, True, False)))
+
+ def test_smaller_than(self):
+ # smaller than B (inclusive)
+ for editable in [
+ # range
+ "{predicate} in [:{num}]", "{predicate} in (:{num}]", "{predicate} in ]:{num}]",
+ "{predicate} : [:{num}]", "{predicate} : (:{num}]", "{predicate} : ]:{num}]",
+ "{predicate} = [:{num}]", "{predicate} = (:{num}]", "{predicate} = ]:{num}]",
+ ]:
+ # positives
+ self._test_number(editable.format(num=1.23, predicate='iso'),
+ (ns.bse.iso, ast.filter.LessThan(1.23, False)))
+ # negatives
+ self._test_number(editable.format(num=-1.23, predicate='iso'),
+ (ns.bse.iso, ast.filter.LessThan(-1.23, False)))
+
+ for editable in [
+ # range
+ "{predicate} in [-{num}]", "{predicate} in (-{num}]", "{predicate} in ]-{num}]",
+ "{predicate} : [-{num}]", "{predicate} : (-{num}]", "{predicate} : ]-{num}]",
+ "{predicate} = [-{num}]", "{predicate} = (-{num}]", "{predicate} = ]-{num}]",
+ # equation
+ "{predicate} <={num}", "{num} >= {predicate}",
+ ]:
+ # positives
+ self._test_number(editable.format(num=1.23, predicate='iso'),
+ (ns.bse.iso, ast.filter.LessThan(1.23, False)))
+ # negatives
+ self._test_number(editable.format(num=-1.23, predicate='iso'),
+ (ns.bse.iso, ast.filter.LessThan(-1.23, False)))
+ # FIXME: date
+ #self._test_number(editable.format(predicate='time', num="30.04.2012, 13:18"),
+ # ('time', ast.Datetime(datetime.min, datetime(2012, 4, 30, 13, 19), False, False)))
+
+ # smaller than B (exclusive)
+ for editable in [
+ # range / bracket
+ "{predicate} in [:{num}[", "{predicate} in (:{num}[", "{predicate} in ]:{num}[",
+ "{predicate} : [:{num}[", "{predicate} : (:{num}[", "{predicate} : ]:{num}[",
+ "{predicate} = [:{num}[", "{predicate} = (:{num}[", "{predicate} = ]:{num}[",
+ # range / parenthesis
+ "{predicate} in [:{num})", "{predicate} in (:{num})", "{predicate} in ]:{num})",
+ "{predicate} : [:{num})", "{predicate} : (:{num})", "{predicate} : ]:{num})",
+ "{predicate} = [:{num})", "{predicate} = (:{num})", "{predicate} = ]:{num})",
+ ]:
+ # positives
+ self._test_number(editable.format(num=1.23, predicate='iso'),
+ (ns.bse.iso, ast.filter.LessThan(1.23, True)))
+ # negatives
+ self._test_number(editable.format(num=-1.23, predicate='iso'),
+ (ns.bse.iso, ast.filter.LessThan(-1.23, True)))
+
+ for editable in [
+ # range / bracket
+ "{predicate} in [-{num}[", "{predicate} in (-{num}[", "{predicate} in ]-{num}[",
+ "{predicate} : [-{num}[", "{predicate} : (-{num}[", "{predicate} : ]-{num}[",
+ "{predicate} = [-{num}[", "{predicate} = (-{num}[", "{predicate} = ]-{num}[",
+ # range / parenthesis
+ "{predicate} in [-{num})", "{predicate} in (-{num})", "{predicate} in ]-{num})",
+ "{predicate} : [-{num})", "{predicate} : (-{num})", "{predicate} : ]-{num})",
+ "{predicate} = [-{num})", "{predicate} = (-{num})", "{predicate} = ]-{num})",
+ # equation
+ "{predicate} <{num}", "{num} > {predicate}",
+ ]:
+ # positives
+ self._test_number(editable.format(num=1.23, predicate='iso'),
+ (ns.bse.iso, ast.filter.LessThan(1.23, True)))
+ # negatives
+ self._test_number(editable.format(num=-1.23, predicate='iso'),
+ (ns.bse.iso, ast.filter.LessThan(-1.23, True)))
+ # FIXME: date
+ #self._test_number(editable.format(predicate='time', num="30.04.2012, 13:18"),
+ # ('time', ast.Datetime(datetime.min, datetime(2012, 4, 30, 13, 18), False, False)))
+
+ def test_between(self):
+ # between A and B (including A, including B)
+ for editable in [
+ # range
+ "{predicate} in [{numA}:{numB}]", "{predicate} : [{numA}:{numB}]", "{predicate} = [{numA}:{numB}]",
+ ]:
+ # positives
+ self._test_number(editable.format(predicate='iso', numA=1.23, numB=4.56),
+ (ns.bse.iso, ast.filter.Between(1.23, 4.56, False, False)))
+ # negatives
+ self._test_number(editable.format(predicate='iso', numA=-4.56, numB=-1.23),
+ (ns.bse.iso, ast.filter.Between(-4.56, -1.23, False, False)))
+ # mixed
+ self._test_number(editable.format(predicate='iso', numA=-1.23, numB=4.56),
+ (ns.bse.iso, ast.filter.Between(-1.23, 4.56, False, False)))
+
+ for editable in [
+ # range
+ "{predicate} in [{numA}-{numB}]", "{predicate} : [{numA}-{numB}]", "{predicate} = [{numA}-{numB}]",
+ # equation
+ "{numA} <= {predicate} <= {numB}"
+ ]:
+ # positives
+ self._test_number(editable.format(predicate='iso', numA=1.23, numB=4.56),
+ (ns.bse.iso, ast.filter.Between(1.23, 4.56, False, False)))
+ # negatives
+ self._test_number(editable.format(predicate='iso', numA=-4.56, numB=-1.23),
+ (ns.bse.iso, ast.filter.Between(-4.56, -1.23, False, False)))
+ # mixed
+ self._test_number(editable.format(predicate='iso', numA=-1.23, numB=4.56),
+ (ns.bse.iso, ast.filter.Between(-1.23, 4.56, False, False)))
+ # FIXME: date
+ #self._test_number(editable.format(predicate='time', numA="30.04.2012, 13:18", numB="13.6.2014, 18:27"),
+ # ('time', ast.Datetime(datetime(2012, 4, 30, 13, 18), datetime(2014, 6, 13, 18, 28), True, False)))
+
+ # between A and B (including A, excluding B)
+ for editable in [
+ # range
+ "{predicate} in [{numA}:{numB})", "{predicate} in [{numA}:{numB}[",
+ "{predicate} : [{numA}:{numB})", "{predicate} : [{numA}:{numB}[",
+ "{predicate} = [{numA}:{numB})", "{predicate} = [{numA}:{numB}[",
+ ]:
+ # positives
+ self._test_number(editable.format(predicate='iso', numA=1.23, numB=4.56),
+ (ns.bse.iso, ast.filter.Between(1.23, 4.56, False, True)))
+ # negatives
+ self._test_number(editable.format(predicate='iso', numA=-4.56, numB=-1.23),
+ (ns.bse.iso, ast.filter.Between(-4.56, -1.23, False, True)))
+ # mixed
+ self._test_number(editable.format(predicate='iso', numA=-1.23, numB=4.56),
+ (ns.bse.iso, ast.filter.Between(-1.23, 4.56, False, True)))
+
+ for editable in [
+ # range
+ "{predicate} in [{numA}-{numB})", "{predicate} in [{numA}-{numB}[",
+ "{predicate} : [{numA}-{numB})", "{predicate} : [{numA}-{numB}[",
+ "{predicate} = [{numA}-{numB})", "{predicate} = [{numA}-{numB}[",
+ # equation
+ "{numA} <= {predicate} < {numB}",
+ ]:
+ # positives
+ self._test_number(editable.format(predicate='iso', numA=1.23, numB=4.56),
+ (ns.bse.iso, ast.filter.Between(1.23, 4.56, False, True)))
+ # negatives
+ self._test_number(editable.format(predicate='iso', numA=-4.56, numB=-1.23),
+ (ns.bse.iso, ast.filter.Between(-4.56, -1.23, False, True)))
+ # mixed
+ self._test_number(editable.format(predicate='iso', numA=-1.23, numB=4.56),
+ (ns.bse.iso, ast.filter.Between(-1.23, 4.56, False, True)))
+ # FIXME: date
+ #self._test_number(editable.format(predicate='time', numA="30.04.2012, 13:18", numB="13.6.2014, 18:27"),
+ # ('time', ast.Datetime(datetime(2012, 4, 30, 13, 18), datetime(2014, 6, 13, 18, 27), True, False)))
+
+ # between A and B (excluding A, including B)
+ for editable in [
+ # range
+ "{predicate} in ({numA}:{numB}]", "{predicate} in ]{numA}:{numB}]",
+ "{predicate} : ({numA}:{numB}]", "{predicate} : ]{numA}:{numB}]",
+ "{predicate} = ({numA}:{numB}]", "{predicate} = ]{numA}:{numB}]",
+ ]:
+ # positives
+ self._test_number(editable.format(predicate='iso', numA=1.23, numB=4.56),
+ (ns.bse.iso, ast.filter.Between(1.23, 4.56, True, False)))
+ # negatives
+ self._test_number(editable.format(predicate='iso', numA=-4.56, numB=-1.23),
+ (ns.bse.iso, ast.filter.Between(-4.56, -1.23, True, False)))
+ # mixed
+ self._test_number(editable.format(predicate='iso', numA=-1.23, numB=4.56),
+ (ns.bse.iso, ast.filter.Between(-1.23, 4.56, True, False)))
+
+ for editable in [
+ # range
+ "{predicate} in ({numA}-{numB}]", "{predicate} in ]{numA}-{numB}]",
+ "{predicate} : ({numA}-{numB}]", "{predicate} : ]{numA}-{numB}]",
+ "{predicate} = ({numA}-{numB}]", "{predicate} = ]{numA}-{numB}]",
+ # equation
+ "{numA} < {predicate} <= {numB}",
+ ]:
+ # positives
+ self._test_number(editable.format(predicate='iso', numA=1.23, numB=4.56),
+ (ns.bse.iso, ast.filter.Between(1.23, 4.56, True, False)))
+ # negatives
+ self._test_number(editable.format(predicate='iso', numA=-4.56, numB=-1.23),
+ (ns.bse.iso, ast.filter.Between(-4.56, -1.23, True, False)))
+ # mixed
+ self._test_number(editable.format(predicate='iso', numA=-1.23, numB=4.56),
+ (ns.bse.iso, ast.filter.Between(-1.23, 4.56, True, False)))
+ # FIXME: date
+ #self._test_number(editable.format(predicate='time', numA="30.04.2012, 13:18", numB="13.6.2014, 18:27"),
+ # ('time', ast.Datetime(datetime(2012, 4, 30, 13, 19), datetime(2014, 6, 13, 18, 28), True, False)))
+
+ # between A and B (excluding A, excluding B)
+ for editable in [
+ "{predicate} in ({numA}:{numB})", "{predicate} in ]{numA}:{numB}[",
+ "{predicate} : ({numA}:{numB})", "{predicate} : ]{numA}:{numB}[",
+ "{predicate} = ({numA}:{numB})", "{predicate} = ]{numA}:{numB}[",
+ ]:
+ # positives
+ self._test_number(editable.format(predicate='iso', numA=1.23, numB=4.56),
+ (ns.bse.iso, ast.filter.Between(1.23, 4.56, True, True)))
+ # negatives
+ self._test_number(editable.format(predicate='iso', numA=-4.56, numB=-1.23),
+ (ns.bse.iso, ast.filter.Between(-4.56, -1.23, True, True)))
+ # mixed
+ self._test_number(editable.format(predicate='iso', numA=-1.23, numB=4.56),
+ (ns.bse.iso, ast.filter.Between(-1.23, 4.56, True, True)))
+
+ for editable in [
+ "{predicate} in ({numA}-{numB})", "{predicate} in ]{numA}-{numB}[",
+ "{predicate} : ({numA}-{numB})", "{predicate} : ]{numA}-{numB}[",
+ "{predicate} = ({numA}-{numB})", "{predicate} = ]{numA}-{numB}[",
+ # equation
+ "{numA} < {predicate} < {numB}",
+ ]:
+ # positives
+ self._test_number(editable.format(predicate='iso', numA=1.23, numB=4.56),
+ (ns.bse.iso, ast.filter.Between(1.23, 4.56, True, True)))
+ # negatives
+ self._test_number(editable.format(predicate='iso', numA=-4.56, numB=-1.23),
+ (ns.bse.iso, ast.filter.Between(-4.56, -1.23, True, True)))
+ # mixed
+ self._test_number(editable.format(predicate='iso', numA=-1.23, numB=4.56),
+ (ns.bse.iso, ast.filter.Between(-1.23, 4.56, True, True)))
+ # FIXME: date
+ #self._test_number(editable.format(predicate='time', numA="30.04.2012, 13:18", numB="13.6.2014, 18:27"),
+ # ('time', ast.Datetime(datetime(2012, 4, 30, 13, 19), datetime(2014, 6, 13, 18, 27), True, False)))
+
+ def test_equal(self):
+ # equal to A
+ for editable in [
+ # range
+ "{predicate} in [{num}:{num}]", "{predicate} : [{num}:{num}]", "{predicate} = [{num}:{num}]",
+ ]:
+ # positives
+ self._test_number(editable.format(predicate='iso', num=1.23),
+ (ns.bse.iso, ast.filter.Equals(1.23)))
+ # negatives
+ self._test_number(editable.format(predicate='iso', num=-1.23),
+ (ns.bse.iso, ast.filter.Equals(-1.23)))
+
+ for editable in [
+ # range
+ "{predicate} in [{num}-{num}]", "{predicate} : [{num}-{num}]", "{predicate} = [{num}-{num}]",
+ # equation
+ "{predicate} = {num}", "{num} = {predicate}",
+ ]:
+ # positives
+ self._test_number(editable.format(predicate='iso', num=1.23),
+ (ns.bse.iso, ast.filter.Equals(1.23)))
+ # negatives
+ self._test_number(editable.format(predicate='iso', num=-1.23),
+ (ns.bse.iso, ast.filter.Equals(-1.23)))
+ # FIXME: date
+ #self._test_number(editable.format(predicate='time', num="30.04.2012, 13:18"),
+ # ('time', ast.Datetime(datetime(2012, 4, 30, 13, 18), datetime(2012, 4, 30, 13, 19), True, False)))
+
+ def test_dates(self):
+ raise NotImplementedError() # FIXME
+ self._test_number("{predicate} < {num}".format(predicate='time', num="2012"),
+ ('time', ast.Datetime(datetime.min, datetime(2012, 1, 1), False, False)))
+ self._test_number("{predicate} < {num}".format(predicate='time', num="2012.04"),
+ ('time', ast.Datetime(datetime.min, datetime(2012, 4, 1), False, False)))
+ self._test_number("{predicate} < {num}".format(predicate='time', num="2012.04.30"),
+ ('time', ast.Datetime(datetime.min, datetime(2012, 4, 30), False, False)))
+ self._test_number("{predicate} < {num}".format(predicate='time', num="2012.04.30, 3 pm"),
+ ('time', ast.Datetime(datetime.min, datetime(2012, 4, 30, 15), False, False)))
+ self._test_number("{predicate} < {num}".format(predicate='time', num="2012.04.30, 15:34"),
+ ('time', ast.Datetime(datetime.min, datetime(2012, 4, 30, 15, 34), False, False)))
+ self._test_number("{predicate} < {num}".format(predicate='time', num="2012.04.30, 15:34:12"),
+ ('time', ast.Datetime(datetime.min, datetime(2012, 4, 30, 15, 34, 12), False, False)))
+ self._test_number("{predicate} < {num}".format(predicate='time', num="2012.04.30, 15:34:12.98"),
+ ('time', ast.Datetime(datetime.min, datetime(2012, 4, 30, 15, 34, 12, 980000), False, False)))
+
+ self._test_number("{predicate} <= {num}".format(predicate='time', num="2012"),
+ ('time', ast.Datetime(datetime.min, datetime(2013, 1, 1), False, False)))
+ self._test_number("{predicate} <= {num}".format(predicate='time', num="2012.04"),
+ ('time', ast.Datetime(datetime.min, datetime(2012, 5, 1), False, False)))
+ self._test_number("{predicate} <= {num}".format(predicate='time', num="2012.04.30"),
+ ('time', ast.Datetime(datetime.min, datetime(2012, 5, 1), False, False)))
+ self._test_number("{predicate} <= {num}".format(predicate='time', num="2012.04.30, 3 pm"),
+ ('time', ast.Datetime(datetime.min, datetime(2012, 4, 30, 16), False, False)))
+ self._test_number("{predicate} <= {num}".format(predicate='time', num="2012.04.30, 15:34"),
+ ('time', ast.Datetime(datetime.min, datetime(2012, 4, 30, 15, 35), False, False)))
+ self._test_number("{predicate} <= {num}".format(predicate='time', num="2012.04.30, 15:34:12"),
+ ('time', ast.Datetime(datetime.min, datetime(2012, 4, 30, 15, 34, 13), False, False)))
+ self._test_number("{predicate} <= {num}".format(predicate='time', num="2012.04.30, 15:34:12.98"),
+ ('time', ast.Datetime(datetime.min, datetime(2012, 4, 30, 15, 34, 12, 980001), False, False)))
+
+ def test_timerange(self):
+ raise NotImplementedError() # FIXME
+ self._test_number("{predicate} < {num}".format(predicate='time', num="15:34"),
+ ('time', ast.TimeRange(datetime.utcfromtimestamp(0.0), datetime(1970, 1, 1, 15, 34), True, False)))
+ self._test_number("{predicate} <= {num}".format(predicate='time', num="15:34"),
+ ('time', ast.TimeRange(datetime.utcfromtimestamp(0.0), datetime(1970, 1, 1, 15, 35), True, False)))
+ self._test_number("{predicate} = {num}".format(predicate='time', num="15:34"),
+ ('time', ast.TimeRange(datetime(1970, 1, 1, 15, 34), datetime(1970, 1, 1, 15, 35), True, False)))
+ self._test_number("{predicate} > {num}".format(predicate='time', num="15:34"),
+ ('time', ast.TimeRange(datetime(1970, 1, 1, 15, 35), datetime(1970, 1, 2), True, True)))
+ self._test_number("{predicate} >= {num}".format(predicate='time', num="15:34"),
+ ('time', ast.TimeRange(datetime(1970, 1, 1, 15, 34), datetime(1970, 1, 2), True, True)))
+
+ self._test_number("{numA} <= {predicate} <= {numB}".format(predicate='time', numA="12:34", numB="15:28"),
+ ('time', ast.TimeRange(datetime(1970, 1, 1, 12, 34), datetime(1970, 1, 1, 15, 29), True, False)))
+ self._test_number("{numA} <= {predicate} < {numB}".format(predicate='time', numA="12:34", numB="15:28"),
+ ('time', ast.TimeRange(datetime(1970, 1, 1, 12, 34), datetime(1970, 1, 1, 15, 28), True, False)))
+ self._test_number("{numA} < {predicate} <= {numB}".format(predicate='time', numA="12:34", numB="15:28"),
+ ('time', ast.TimeRange(datetime(1970, 1, 1, 12, 35), datetime(1970, 1, 1, 15, 29), True, False)))
+ self._test_number("{numA} < {predicate} < {numB}".format(predicate='time', numA="12:34", numB="15:28"),
+ ('time', ast.TimeRange(datetime(1970, 1, 1, 12, 35), datetime(1970, 1, 1, 15, 28), True, False)))
+
+ def test_special(self):
+ # special cases: explicit plus sign
+ self._test_number("{predicate} in [+1.23-+4.56]".format(predicate='iso'),
+ (ns.bse.iso, ast.filter.Between(1.23, 4.56, False, False)))
+ self._test_number("{predicate} in [-+4.56]".format(predicate='iso'),
+ (ns.bse.iso, ast.filter.LessThan(4.56, False)))
+
+ def test_errors(self):
+ # parse errors
+ for editable in [
+ # equal with exclusive
+ "{predicate} in ({num}:{num})", "{predicate} in ({num}-{num})",
+ "{predicate} in ({num}:{num}[", "{predicate} in ({num}-{num}[",
+ "{predicate} in ]{num}:{num})", "{predicate} in ]{num}-{num})",
+ "{predicate} in ]{num}:{num}[", "{predicate} in ]{num}-{num}[",
+ # invalid parentesis
+ "{predicate} in ){num}:{num}(",
+ # misc errors
+ # FIXME: Currently all special characters are allowed as categorical value.
+ # If this changes, don't forget to enable the tests below.
+ #"{predicate} in [{num}{num}]",
+ #"{predicate} [{num}:{num}:{num}]",
+ #"{predicate} = ({num})",
+ #"{predicate} = {num})",
+ ]:
+ self.assertRaises(errors.ParserError, self.parse,
+ editable.format(predicate='iso', num=1.23))
+
+ for editable in [
+ "{predicate} in [{numA}:{numB}]", "{predicate} : [{numA}:{numB}]", "{predicate} = [{numA}:{numB}]",
+ "{predicate} in ]{numA}:{numB}]", "{predicate} : ]{numA}:{numB}]", "{predicate} = ]{numA}:{numB}]",
+ "{predicate} in [{numA}:{numB}[", "{predicate} : [{numA}:{numB}[", "{predicate} = [{numA}:{numB}[",
+ "{predicate} in ({numA}:{numB}]", "{predicate} : ({numA}:{numB}]", "{predicate} = ({numA}:{numB}]",
+ "{predicate} in [{numA}:{numB})", "{predicate} : [{numA}:{numB})", "{predicate} = [{numA}:{numB})",
+ "{predicate} in ]{numA}:{numB}[", "{predicate} : ]{numA}:{numB}[", "{predicate} = ]{numA}:{numB}[",
+ "{predicate} in ]{numA}:{numB})", "{predicate} : ]{numA}:{numB})", "{predicate} = ]{numA}:{numB})",
+ "{predicate} in ({numA}:{numB}[", "{predicate} : ({numA}:{numB}[", "{predicate} = ({numA}:{numB}[",
+ "{predicate} in ({numA}:{numB})", "{predicate} : ({numA}:{numB})", "{predicate} = ({numA}:{numB})",
+ "{numA} < {predicate} < {numB}",
+ "{numA} <= {predicate} < {numB}",
+ "{numA} < {predicate} <= {numB}",
+ ]:
+ self.assertRaises(errors.ParserError, self.parse,
+ editable.format(predicate='iso', numA=4.56, numB=1.23))
+ # FIXME:
+ #self.assertRaises(errors.ParserError, self.parse,
+ # editable.format(predicate='time', numA="17:35", numB="10:55"))
+ #self.assertRaises(errors.ParserError, self.parse,
+ # editable.format(predicate='time', numA="18.12.2035", numB="5.7.1999"))
+
+ raise NotImplementedError() # FIXME
+ # special cases: empty range with boundary
+ self.assertRaises(ParseException, ast_from_string.CONTINUOUS.parseString,
+ "{predicate} in [:]".format(predicate='iso'))
+ self.assertRaises(ParseException, ast_from_string.CONTINUOUS.parseString,
+ "{predicate} in (:[".format(predicate='iso'))
+ self.assertRaises(ParseException, ast_from_string.CONTINUOUS.parseString,
+ "{predicate} in ]:)".format(predicate='iso'))
+ self.assertRaises(ParseException, ast_from_string.CONTINUOUS.parseString,
+ "{predicate} in ".format(predicate='iso'))
+ # misc
+ self.assertRaises(ParseException, ast_from_string.CONTINUOUS.parseString,
+ "{predicate} in [{num}{num}]".format(predicate='iso', num=1.23))
+ self.assertRaises(ParseException, ast_from_string.CONTINUOUS.parseString,
+ "{predicate} [{num}:{num}:{num}]".format(predicate='iso', num=1.23))
+ self.assertRaises(ParseException, ast_from_string.CONTINUOUS.parseString,
+ "{predicate} = ({num})".format(predicate='iso', num=1.23))
+ self.assertRaises(ParseException, ast_from_string.CONTINUOUS.parseString,
+ "{predicate} = ({num}".format(predicate='iso', num=1.23), dict(parseAll=True))
+ self.assertRaises(ParseException, ast_from_string.CONTINUOUS.parseString,
+ "{predicate} = {num})".format(predicate='iso', num=1.23), dict(parseAll=True))
+ # range errors
+ self.assertRaises(errors.ParserError, self.parse, "100 >= iso < 200")
+ self.assertRaises(errors.ParserError, self.parse, "100 > iso < 200")
+ self.assertRaises(errors.ParserError, self.parse, "100 > iso <= 200")
+ self.assertRaises(errors.ParserError, self.parse, "100 >= iso <= 200")
+ self.assertRaises(errors.ParserError, self.parse, "100 = iso = 200")
+ # time/date mixture errors
+ self.assertRaises(errors.ParserError, self.parse, "12:45 < time < 17.5.2004")
+ self.assertRaises(errors.ParserError, self.parse, "17.5.2004 < time < 12:45")
+ # date/int mixture errors
+ self.assertRaises(errors.ParserError, self.parse, "17.5.2004 < time < 1245")
+ # 1245 is interpreted as the year
+ #self.assertRaises(errors.ParserError, self.parse, "1245 < time < 17.5.2004")
+ # time/int mixture errors
+ self.assertRaises(errors.ParserError, self.parse, "17:12 < time < 1245")
+ self.assertRaises(errors.ParserError, self.parse, "1712 < time < 12:45")
+
+ # empty query
+ self.assertRaises(ParseException, ast_from_string.CONTINUOUS.parseString, "")
+
+
+
+
+ def _test(self, query, target):
+ result = self.parse(query)
+ target = ast.filter.And(target)
+ self.assertEqual(result, target, msg="in query '{}'".format(query))
+
+ def test_parse_existence(self):
+ self._test('has mime',
+ ast.filter.Has(ns.bse.mime))
+ self._test('has no mime',
+ ast.filter.Not(ast.filter.Has(ns.bse.mime)))
+ self._test('has not mime',
+ ast.filter.Not(ast.filter.Has(ns.bse.mime)))
+
+ def test_parse_categorical(self):
+ # positive
+ self._test("iso in 100, 200, 500",
+ ast.filter.Any(ns.bse.iso, ast.filter.Includes('100', '200', '500')))
+ self._test("iso in (100, 200)",
+ ast.filter.Any(ns.bse.iso, ast.filter.Includes('100', '200')))
+ self._test("iso = (100, 200)",
+ ast.filter.Any(ns.bse.iso, ast.filter.Includes('100', '200')))
+ # FIXME!
+ #self._test("iso = 100, 200",
+ # ast.filter.Any(ns.bse.iso, ast.filter.Includes('100', '200')))
+ self._test("iso : (100, 200)",
+ ast.filter.Any(ns.bse.iso, ast.filter.Includes('100', '200')))
+ self._test("iso : 100, 200",
+ ast.filter.Any(ns.bse.iso, ast.filter.Includes('100', '200')))
+ self._test("iso:(100,200)",
+ ast.filter.Any(ns.bse.iso, ast.filter.Includes('100', '200')))
+ self._test("iso in (100,200)",
+ ast.filter.Any(ns.bse.iso, ast.filter.Includes('100', '200')))
+ self._test("iso in 100,200",
+ ast.filter.Any(ns.bse.iso, ast.filter.Includes('100', '200')))
+ self._test("iso ~ (100,200)",
+ ast.filter.Any(ns.bse.iso, ast.filter.Includes('100', '200', approx=True)))
+ self._test("iso ~ 100,200",
+ ast.filter.Any(ns.bse.iso, ast.filter.Includes('100', '200', approx=True)))
+
+ # negative
+ self._test("iso not in 100,200",
+ ast.filter.All(ns.bse.iso, ast.filter.Excludes('100', '200')))
+ self._test("iso not in (100, 200)",
+ ast.filter.All(ns.bse.iso, ast.filter.Excludes('100', '200')))
+ self._test("iso != 100,200",
+ ast.filter.All(ns.bse.iso, ast.filter.Excludes('100', '200')))
+ self._test("iso != (100, 200)",
+ ast.filter.All(ns.bse.iso, ast.filter.Excludes('100', '200')))
+ self._test("iso !~ 100,200",
+ ast.filter.All(ns.bse.iso, ast.filter.Excludes('100', '200', approx=True)))
+ self._test("iso !~ (100, 200)",
+ ast.filter.All(ns.bse.iso, ast.filter.Excludes('100', '200', approx=True)))
+
+ # one value
+ self._test("mime : text",
+ ast.filter.Any(ns.bse.mime, ast.filter.Includes('text')))
+ self._test("mime in text",
+ ast.filter.Any(ns.bse.mime, ast.filter.Includes('text')))
+ self._test("mime = text",
+ ast.filter.Any(ns.bse.mime, ast.filter.Includes('text')))
+ self._test("mime ~ text",
+ ast.filter.Any(ns.bse.mime, ast.filter.Includes('text', approx=True)))
+ self._test("mime != text",
+ ast.filter.All(ns.bse.mime, ast.filter.Excludes('text')))
+ self._test("mime not in text",
+ ast.filter.All(ns.bse.mime, ast.filter.Excludes('text')))
+ self._test("mime !~ text",
+ ast.filter.All(ns.bse.mime, ast.filter.Excludes('text', approx=True)))
+
+ # expressions with slash and comma
+ self._test('mime : "text"',
+ ast.filter.Any(ns.bse.mime, ast.filter.Includes('text')))
+ self._test('mime : "text", "plain"',
+ ast.filter.Any(ns.bse.mime, ast.filter.Includes('text', 'plain')))
+ self._test('mime : "text, plain"',
+ ast.filter.Any(ns.bse.mime, ast.filter.Includes('text, plain')))
+ self._test('mime ~ "text/plain"',
+ ast.filter.Any(ns.bse.mime, ast.filter.Includes('text/plain', approx=True)))
+ self._test('mime = ("text/plain", "image/jpeg")',
+ ast.filter.Any(ns.bse.mime, ast.filter.Includes('text/plain', 'image/jpeg')))
+
+ def test_parse_tag(self):
+ # only tag: tag, tags, (tag), (tags)
+ self._test("foo",
+ ast.filter.Any(ns.bse.tag, ast.filter.Any(ns.bst.label, ast.filter.Equals('foo'))))
+ self._test("(foo)",
+ ast.filter.Any(ns.bse.tag, ast.filter.Any(ns.bst.label, ast.filter.Equals('foo'))))
+ self._test("foo, bar",
+ ast.filter.Any(ns.bse.tag, ast.filter.Any(ns.bst.label, ast.filter.Includes('foo', 'bar'))))
+ self._test("foo,bar",
+ ast.filter.Any(ns.bse.tag, ast.filter.Any(ns.bst.label, ast.filter.Includes('foo', 'bar'))))
+ self._test("(foo, bar,foobar)",
+ ast.filter.Any(ns.bse.tag, ast.filter.Any(ns.bst.label, ast.filter.Includes('foo', 'bar', 'foobar'))))
+
+ # op and tag: !tag, ~tag, !~tag
+ self._test("~foo",
+ ast.filter.Any(ns.bse.tag, ast.filter.Any(ns.bst.label, ast.filter.Substring('foo'))))
+ self._test("~ foo",
+ ast.filter.Any(ns.bse.tag, ast.filter.Any(ns.bst.label, ast.filter.Substring('foo'))))
+ self._test("!foo",
+ ast.filter.All(ns.bse.tag, ast.filter.Any(ns.bst.label, ast.filter.Not(ast.filter.Equals('foo')))))
+ self._test("! foo",
+ ast.filter.All(ns.bse.tag, ast.filter.Any(ns.bst.label, ast.filter.Not(ast.filter.Equals('foo')))))
+ self._test("!~foo",
+ ast.filter.All(ns.bse.tag, ast.filter.Any(ns.bst.label, ast.filter.Not(ast.filter.Substring('foo')))))
+ self._test("!~ foo",
+ ast.filter.All(ns.bse.tag, ast.filter.Any(ns.bst.label, ast.filter.Not(ast.filter.Substring('foo')))))
+
+ # op and list: ! (tags), ~tags, ...
+ self._test("~ foo, bar",
+ ast.filter.Any(ns.bse.tag, ast.filter.Any(ns.bst.label, ast.filter.Includes('foo', 'bar', approx=True))))
+ self._test("~foo, bar",
+ ast.filter.Any(ns.bse.tag, ast.filter.Any(ns.bst.label, ast.filter.Includes('foo', 'bar', approx=True))))
+ self._test("~ (foo, bar)",
+ ast.filter.Any(ns.bse.tag, ast.filter.Any(ns.bst.label, ast.filter.Includes('foo', 'bar', approx=True))))
+ self._test("! foo, bar",
+ ast.filter.All(ns.bse.tag, ast.filter.Any(ns.bst.label, ast.filter.Excludes('foo', 'bar'))))
+ self._test("! (foo, bar)",
+ ast.filter.All(ns.bse.tag, ast.filter.Any(ns.bst.label, ast.filter.Excludes('foo', 'bar'))))
+ self._test("! (foo,bar)",
+ ast.filter.All(ns.bse.tag, ast.filter.Any(ns.bst.label, ast.filter.Excludes('foo', 'bar'))))
+ self._test("!~ foo, bar",
+ ast.filter.All(ns.bse.tag, ast.filter.Any(ns.bst.label, ast.filter.Excludes('foo', 'bar', approx=True))))
+ self._test("!~ (foo, bar)",
+ ast.filter.All(ns.bse.tag, ast.filter.Any(ns.bst.label, ast.filter.Excludes('foo', 'bar', approx=True))))
+ self._test("!~(foo,bar)",
+ ast.filter.All(ns.bse.tag, ast.filter.Any(ns.bst.label, ast.filter.Excludes('foo', 'bar', approx=True))))
+
+ def test_parse_query(self):
+ # simple query
+ self.assertEqual(self.parse('foo / bar'), ast.filter.And(
+ ast.filter.Any(ns.bse.tag, ast.filter.Any(ns.bst.label, ast.filter.Equals('foo'))),
+ ast.filter.Any(ns.bse.tag, ast.filter.Any(ns.bst.label, ast.filter.Equals('bar')))))
+ self.assertEqual(self.parse('iso in ("foo", "bar") / mime = plain'), ast.filter.And(
+ ast.filter.Any(ns.bse.iso, ast.filter.Includes('foo', 'bar')),
+ ast.filter.Any(ns.bse.mime, ast.filter.Equals('plain'))))
+ self.assertEqual(self.parse('iso in ("foo", "bar") / mime = plain'), ast.filter.And(
+ ast.filter.Any(ns.bse.iso, ast.filter.Includes('foo', 'bar')),
+ ast.filter.Any(ns.bse.mime, ast.filter.Equals('plain'))))
+ self.assertEqual(self.parse('iso = 1.23 / rank < 5'), ast.filter.And(
+ ast.filter.Any(ns.bse.iso, ast.filter.Equals(1.23)),
+ ast.filter.Any(ns.bse.rank, ast.filter.LessThan(5, True))))
+ # FIXME
+ #self.assertEqual(self.parse('time >= 12:50 / time < 13:50'), ast.filter.And(
+ # ast.filter.Any(ns.bse.time, ast.TimeRange(lo=datetime(1970, 1, 1, 12, 50), lo_inc=True, hi_inc=True)),
+ # ast.filter.Any(ns.bse.time, ast.TimeRange(hi=datetime(1970, 1, 1, 13, 50), lo_inc=True, hi_inc=False))))
+ #self.assertEqual(self.parse('time >= 17.5.2001 / time < 18.4.2002'), ast.filter.And(
+ # ast.filter.Any(ns.bse.time, ast.Datetime(lo=datetime(2001, 5, 17, 0, 0), lo_inc=True)),
+ # ast.filter.Any(ns.bse.time, ast.Datetime(hi=datetime(2002, 4, 18, 0, 0)))))
+ # mixing expressions
+ #self.assertEqual(self.parse('foo / iso in "bar" / mime ~ "text/plain" / iso < 100 / time >= 17.5.2001 / time < 13:50'), ast.filter.And(
+ # ast.filter.Any(ns.bse.tag, ast.filter.Equals('foo')),
+ # ast.filter.Any(ns.bse.iso, ast.filter.Equals('bar')),
+ # ast.filter.Any(ns.bse.mime, ast.filter.Substring('text/plain')),
+ # ast.filter.Any(ns.bse.iso, ast.filter.LessThan(100)),
+ # ast.filter.Any(ns.bse.time, ast.Datetime(lo=datetime(2001, 5, 17, 0, 0), lo_inc=True)),
+ # ast.filter.Any(ns.bse.time, ast.TimeRange(hi=datetime(1970, 1, 1, 13, 50), lo_inc=True))))
+
+ # leading/trailing slashes
+ self.assertRaises(errors.ParserError, self.parse, '/ foobar')
+ self.assertRaises(errors.ParserError, self.parse, 'foobar /')
+ self.assertRaises(errors.ParserError, self.parse, 'foobar / ')
+ self.assertRaises(errors.ParserError, self.parse, 'foo // bar')
+ self.assertRaises(errors.ParserError, self.parse, 'foo / / bar')
+
+ def test_quoting(self):
+ self._test("tag in ('(foo, bar)', foobar)",
+ ast.filter.Any(ns.bse.tag, ast.filter.Includes('(foo, bar)', 'foobar')))
+ self._test('tag in ("(foo, bar)", foobar)',
+ ast.filter.Any(ns.bse.tag, ast.filter.Includes('(foo, bar)', 'foobar')))
+ self._test('tag in ("(foo, \\"bar\\")", foobar)',
+ ast.filter.Any(ns.bse.tag, ast.filter.Includes('(foo, "bar")', 'foobar')))
+ self._test('tag in ("(foo, bar)", "foobar")',
+ ast.filter.Any(ns.bse.tag, ast.filter.Includes('(foo, bar)', 'foobar')))
+ self._test('tag in ("(foo, bar)", \'foobar\')',
+ ast.filter.Any(ns.bse.tag, ast.filter.Includes('(foo, bar)', 'foobar')))
+
+ # error cases
+ self.assertRaises(errors.ParserError, self.parse, ('tag in ("(foo, bar, foobar)'))
+ self.assertRaises(errors.ParserError, self.parse, ("tag in ('(foo, bar, foobar)"))
+
+
+## main ##
+
+if __name__ == '__main__':
+ unittest.main()
+
+## EOF ##
diff --git a/test/parsing/test_search.py b/test/parsing/test_search.py
deleted file mode 100644
index 23801d0..0000000
--- a/test/parsing/test_search.py
+++ /dev/null
@@ -1,707 +0,0 @@
-"""
-
-Part of the tagit test suite.
-A copy of the license is provided with the project.
-Author: Matthias Baumgartner, 2022
-"""
-# standard imports
-import unittest
-from datetime import datetime
-
-# external imports
-from pyparsing import ParseException
-
-# tagit imports
-from tagit.utils import errors
-#from tagit.parsing.search import ast, predicates, PredicateScope # FIXME: mb/port/parsing
-
-# objects to test
-from tagit.parsing.search import ast_from_string
-
-
-## code ##
-
-class TestScope(PredicateScope):
- _scope_order = ['major', 'minor', 'micro']
- _init_values = ['library']
-
-
-class TestParseContinuous(unittest.TestCase):
- longMessage = True
-
- def setUp(self):
- predicates.expose('mime',
- TestScope('attribute', 'mime'), 'Categorical')
- predicates.expose('iso',
- TestScope('attribute', 'iso'), 'Continuous', 'Categorical')
- predicates.expose('time',
- TestScope('generic', 't_image_create_loc'), 'TimeRange', 'Datetime')
- predicates.expose('tag',
- TestScope('generic', 'tag'), 'Categorical')
-
- def _test(self, query, target):
- predicate, condition = target
- result = ast_from_string(query)
- target = ast.AND([ast.Token(predicate, condition)])
- self.assertEqual(result, target, msg="in query '{}'".format(query))
-
- def test_larger_than(self):
- # larger than A (inclusive)
- for editable in [
- # range
- "{predicate} in [{num}:]", "{predicate} in [{num}:[", "{predicate} in [{num}:)",
- "{predicate} : [{num}:]", "{predicate} : [{num}:[", "{predicate} : [{num}:)",
- "{predicate} = [{num}:]", "{predicate} = [{num}:[", "{predicate} = [{num}:)",
- ]:
- # positive
- self._test(editable.format(num=1.23, predicate='iso'),
- ('iso', ast.Continuous(1.23, float('inf'), True, False)))
- # negative
- self._test(editable.format(num=-1.23, predicate='iso'),
- ('iso', ast.Continuous(-1.23, float('inf'), True, False)))
-
- for editable in [
- # range
- "{predicate} in [{num}-]", "{predicate} in [{num}-[", "{predicate} in [{num}-)",
- "{predicate} : [{num}-]", "{predicate} : [{num}-[", "{predicate} : [{num}-)",
- "{predicate} = [{num}-]", "{predicate} = [{num}-[", "{predicate} = [{num}-)",
- # equation
- "{predicate} >= {num}", "{num} <= {predicate}",
- ]:
- # positive
- self._test(editable.format(num=1.23, predicate='iso'),
- ('iso', ast.Continuous(1.23, float('inf'), True, False)))
- # negative
- self._test(editable.format(num=-1.23, predicate='iso'),
- ('iso', ast.Continuous(-1.23, float('inf'), True, False)))
- # date
- self._test(editable.format(predicate='time', num="30.04.2012, 13:18"),
- ('time', ast.Datetime(datetime(2012, 4, 30, 13, 18), datetime.max, True, False)))
-
- # larger than A (exclusive)
- for editable in [
- # range / bracket
- "{predicate} in ]{num}:]", "{predicate} in ]{num}:[", "{predicate} in ]{num}:)",
- "{predicate} : ]{num}:]", "{predicate} : ]{num}:[", "{predicate} : ]{num}:)",
- "{predicate} = ]{num}:]", "{predicate} = ]{num}:[", "{predicate} = ]{num}:)",
- # range / parenthesis
- "{predicate} in ({num}:]", "{predicate} in ({num}:[", "{predicate} in ({num}:)",
- "{predicate} : ({num}:]", "{predicate} : ({num}:[", "{predicate} : ({num}:)",
- "{predicate} = ({num}:]", "{predicate} = ({num}:[", "{predicate} = ({num}:)",
- ]:
- # positive
- self._test(editable.format(num=1.23, predicate='iso'),
- ('iso', ast.Continuous(1.23, float('inf'), False, False)))
- # negative
- self._test(editable.format(num=-1.23, predicate='iso'),
- ('iso', ast.Continuous(-1.23, float('inf'), False, False)))
-
- for editable in [
- # range / bracket
- "{predicate} in ]{num}-]", "{predicate} in ]{num}-[", "{predicate} in ]{num}-)",
- "{predicate} : ]{num}-]", "{predicate} : ]{num}-[", "{predicate} : ]{num}-)",
- "{predicate} = ]{num}-]", "{predicate} = ]{num}-[", "{predicate} = ]{num}-)",
- # range / parenthesis
- "{predicate} in ({num}-]", "{predicate} in ({num}-[", "{predicate} in ({num}-)",
- "{predicate} : ({num}-]", "{predicate} : ({num}-[", "{predicate} : ({num}-)",
- "{predicate} = ({num}-]", "{predicate} = ({num}-[", "{predicate} = ({num}-)",
- # equation
- "{predicate} > {num}", "{num} < {predicate}",
- ]:
- # positive
- self._test(editable.format(num=1.23, predicate='iso'),
- ('iso', ast.Continuous(1.23, float('inf'), False, False)))
- # negative
- self._test(editable.format(num=-1.23, predicate='iso'),
- ('iso', ast.Continuous(-1.23, float('inf'), False, False)))
- # date
- self._test(editable.format(predicate='time', num="30.04.2012, 13:18"),
- ('time', ast.Datetime(datetime(2012, 4, 30, 13, 19), datetime.max, True, False)))
-
- def test_smaller_than(self):
- # smaller than B (inclusive)
- for editable in [
- # range
- "{predicate} in [:{num}]", "{predicate} in (:{num}]", "{predicate} in ]:{num}]",
- "{predicate} : [:{num}]", "{predicate} : (:{num}]", "{predicate} : ]:{num}]",
- "{predicate} = [:{num}]", "{predicate} = (:{num}]", "{predicate} = ]:{num}]",
- ]:
- # positives
- self._test(editable.format(num=1.23, predicate='iso'),
- ('iso', ast.Continuous(float('-inf'), 1.23, False, True)))
- # negatives
- self._test(editable.format(num=-1.23, predicate='iso'),
- ('iso', ast.Continuous(float('-inf'), -1.23, False, True)))
-
- for editable in [
- # range
- "{predicate} in [-{num}]", "{predicate} in (-{num}]", "{predicate} in ]-{num}]",
- "{predicate} : [-{num}]", "{predicate} : (-{num}]", "{predicate} : ]-{num}]",
- "{predicate} = [-{num}]", "{predicate} = (-{num}]", "{predicate} = ]-{num}]",
- # equation
- "{predicate} <={num}", "{num} >= {predicate}",
- ]:
- # positives
- self._test(editable.format(num=1.23, predicate='iso'),
- ('iso', ast.Continuous(float('-inf'), 1.23, False, True)))
- # negatives
- self._test(editable.format(num=-1.23, predicate='iso'),
- ('iso', ast.Continuous(float('-inf'), -1.23, False, True)))
- # date
- self._test(editable.format(predicate='time', num="30.04.2012, 13:18"),
- ('time', ast.Datetime(datetime.min, datetime(2012, 4, 30, 13, 19), False, False)))
-
- # smaller than B (exclusive)
- for editable in [
- # range / bracket
- "{predicate} in [:{num}[", "{predicate} in (:{num}[", "{predicate} in ]:{num}[",
- "{predicate} : [:{num}[", "{predicate} : (:{num}[", "{predicate} : ]:{num}[",
- "{predicate} = [:{num}[", "{predicate} = (:{num}[", "{predicate} = ]:{num}[",
- # range / parenthesis
- "{predicate} in [:{num})", "{predicate} in (:{num})", "{predicate} in ]:{num})",
- "{predicate} : [:{num})", "{predicate} : (:{num})", "{predicate} : ]:{num})",
- "{predicate} = [:{num})", "{predicate} = (:{num})", "{predicate} = ]:{num})",
- ]:
- # positives
- self._test(editable.format(num=1.23, predicate='iso'),
- ('iso', ast.Continuous(float('-inf'), 1.23, False, False)))
- # negatives
- self._test(editable.format(num=-1.23, predicate='iso'),
- ('iso', ast.Continuous(float('-inf'), -1.23, False, False)))
-
- for editable in [
- # range / bracket
- "{predicate} in [-{num}[", "{predicate} in (-{num}[", "{predicate} in ]-{num}[",
- "{predicate} : [-{num}[", "{predicate} : (-{num}[", "{predicate} : ]-{num}[",
- "{predicate} = [-{num}[", "{predicate} = (-{num}[", "{predicate} = ]-{num}[",
- # range / parenthesis
- "{predicate} in [-{num})", "{predicate} in (-{num})", "{predicate} in ]-{num})",
- "{predicate} : [-{num})", "{predicate} : (-{num})", "{predicate} : ]-{num})",
- "{predicate} = [-{num})", "{predicate} = (-{num})", "{predicate} = ]-{num})",
- # equation
- "{predicate} <{num}", "{num} > {predicate}",
- ]:
- # positives
- self._test(editable.format(num=1.23, predicate='iso'),
- ('iso', ast.Continuous(float('-inf'), 1.23, False, False)))
- # negatives
- self._test(editable.format(num=-1.23, predicate='iso'),
- ('iso', ast.Continuous(float('-inf'), -1.23, False, False)))
- # date
- self._test(editable.format(predicate='time', num="30.04.2012, 13:18"),
- ('time', ast.Datetime(datetime.min, datetime(2012, 4, 30, 13, 18), False, False)))
-
- def test_between(self):
- # between A and B (including A, including B)
- for editable in [
- # range
- "{predicate} in [{numA}:{numB}]", "{predicate} : [{numA}:{numB}]", "{predicate} = [{numA}:{numB}]",
- ]:
- # positives
- self._test(editable.format(predicate='iso', numA=1.23, numB=4.56),
- ('iso', ast.Continuous(1.23, 4.56, True, True)))
- # negatives
- self._test(editable.format(predicate='iso', numA=-4.56, numB=-1.23),
- ('iso', ast.Continuous(-4.56, -1.23, True, True)))
- # mixed
- self._test(editable.format(predicate='iso', numA=-1.23, numB=4.56),
- ('iso', ast.Continuous(-1.23, 4.56, True, True)))
-
- for editable in [
- # range
- "{predicate} in [{numA}-{numB}]", "{predicate} : [{numA}-{numB}]", "{predicate} = [{numA}-{numB}]",
- # equation
- "{numA} <= {predicate} <= {numB}"
- ]:
- # positives
- self._test(editable.format(predicate='iso', numA=1.23, numB=4.56),
- ('iso', ast.Continuous(1.23, 4.56, True, True)))
- # negatives
- self._test(editable.format(predicate='iso', numA=-4.56, numB=-1.23),
- ('iso', ast.Continuous(-4.56, -1.23, True, True)))
- # mixed
- self._test(editable.format(predicate='iso', numA=-1.23, numB=4.56),
- ('iso', ast.Continuous(-1.23, 4.56, True, True)))
- # date
- self._test(editable.format(predicate='time', numA="30.04.2012, 13:18", numB="13.6.2014, 18:27"),
- ('time', ast.Datetime(datetime(2012, 4, 30, 13, 18), datetime(2014, 6, 13, 18, 28), True, False)))
-
- # between A and B (including A, excluding B)
- for editable in [
- # range
- "{predicate} in [{numA}:{numB})", "{predicate} in [{numA}:{numB}[",
- "{predicate} : [{numA}:{numB})", "{predicate} : [{numA}:{numB}[",
- "{predicate} = [{numA}:{numB})", "{predicate} = [{numA}:{numB}[",
- ]:
- # positives
- self._test(editable.format(predicate='iso', numA=1.23, numB=4.56),
- ('iso', ast.Continuous(1.23, 4.56, True, False)))
- # negatives
- self._test(editable.format(predicate='iso', numA=-4.56, numB=-1.23),
- ('iso', ast.Continuous(-4.56, -1.23, True, False)))
- # mixed
- self._test(editable.format(predicate='iso', numA=-1.23, numB=4.56),
- ('iso', ast.Continuous(-1.23, 4.56, True, False)))
-
- for editable in [
- # range
- "{predicate} in [{numA}-{numB})", "{predicate} in [{numA}-{numB}[",
- "{predicate} : [{numA}-{numB})", "{predicate} : [{numA}-{numB}[",
- "{predicate} = [{numA}-{numB})", "{predicate} = [{numA}-{numB}[",
- # equation
- "{numA} <= {predicate} < {numB}",
- ]:
- # positives
- self._test(editable.format(predicate='iso', numA=1.23, numB=4.56),
- ('iso', ast.Continuous(1.23, 4.56, True, False)))
- # negatives
- self._test(editable.format(predicate='iso', numA=-4.56, numB=-1.23),
- ('iso', ast.Continuous(-4.56, -1.23, True, False)))
- # mixed
- self._test(editable.format(predicate='iso', numA=-1.23, numB=4.56),
- ('iso', ast.Continuous(-1.23, 4.56, True, False)))
- # date
- self._test(editable.format(predicate='time', numA="30.04.2012, 13:18", numB="13.6.2014, 18:27"),
- ('time', ast.Datetime(datetime(2012, 4, 30, 13, 18), datetime(2014, 6, 13, 18, 27), True, False)))
-
- # between A and B (excluding A, including B)
- for editable in [
- # range
- "{predicate} in ({numA}:{numB}]", "{predicate} in ]{numA}:{numB}]",
- "{predicate} : ({numA}:{numB}]", "{predicate} : ]{numA}:{numB}]",
- "{predicate} = ({numA}:{numB}]", "{predicate} = ]{numA}:{numB}]",
- ]:
- # positives
- self._test(editable.format(predicate='iso', numA=1.23, numB=4.56),
- ('iso', ast.Continuous(1.23, 4.56, False, True)))
- # negatives
- self._test(editable.format(predicate='iso', numA=-4.56, numB=-1.23),
- ('iso', ast.Continuous(-4.56, -1.23, False, True)))
- # mixed
- self._test(editable.format(predicate='iso', numA=-1.23, numB=4.56),
- ('iso', ast.Continuous(-1.23, 4.56, False, True)))
-
- for editable in [
- # range
- "{predicate} in ({numA}-{numB}]", "{predicate} in ]{numA}-{numB}]",
- "{predicate} : ({numA}-{numB}]", "{predicate} : ]{numA}-{numB}]",
- "{predicate} = ({numA}-{numB}]", "{predicate} = ]{numA}-{numB}]",
- # equation
- "{numA} < {predicate} <= {numB}",
- ]:
- # positives
- self._test(editable.format(predicate='iso', numA=1.23, numB=4.56),
- ('iso', ast.Continuous(1.23, 4.56, False, True)))
- # negatives
- self._test(editable.format(predicate='iso', numA=-4.56, numB=-1.23),
- ('iso', ast.Continuous(-4.56, -1.23, False, True)))
- # mixed
- self._test(editable.format(predicate='iso', numA=-1.23, numB=4.56),
- ('iso', ast.Continuous(-1.23, 4.56, False, True)))
- # date
- self._test(editable.format(predicate='time', numA="30.04.2012, 13:18", numB="13.6.2014, 18:27"),
- ('time', ast.Datetime(datetime(2012, 4, 30, 13, 19), datetime(2014, 6, 13, 18, 28), True, False)))
-
- # between A and B (excluding A, excluding B)
- for editable in [
- "{predicate} in ({numA}:{numB})", "{predicate} in ]{numA}:{numB}[",
- "{predicate} : ({numA}:{numB})", "{predicate} : ]{numA}:{numB}[",
- "{predicate} = ({numA}:{numB})", "{predicate} = ]{numA}:{numB}[",
- ]:
- # positives
- self._test(editable.format(predicate='iso', numA=1.23, numB=4.56),
- ('iso', ast.Continuous(1.23, 4.56, False, False)))
- # negatives
- self._test(editable.format(predicate='iso', numA=-4.56, numB=-1.23),
- ('iso', ast.Continuous(-4.56, -1.23, False, False)))
- # mixed
- self._test(editable.format(predicate='iso', numA=-1.23, numB=4.56),
- ('iso', ast.Continuous(-1.23, 4.56, False, False)))
-
- for editable in [
- "{predicate} in ({numA}-{numB})", "{predicate} in ]{numA}-{numB}[",
- "{predicate} : ({numA}-{numB})", "{predicate} : ]{numA}-{numB}[",
- "{predicate} = ({numA}-{numB})", "{predicate} = ]{numA}-{numB}[",
- # equation
- "{numA} < {predicate} < {numB}",
- ]:
- # positives
- self._test(editable.format(predicate='iso', numA=1.23, numB=4.56),
- ('iso', ast.Continuous(1.23, 4.56, False, False)))
- # negatives
- self._test(editable.format(predicate='iso', numA=-4.56, numB=-1.23),
- ('iso', ast.Continuous(-4.56, -1.23, False, False)))
- # mixed
- self._test(editable.format(predicate='iso', numA=-1.23, numB=4.56),
- ('iso', ast.Continuous(-1.23, 4.56, False, False)))
- # date
- self._test(editable.format(predicate='time', numA="30.04.2012, 13:18", numB="13.6.2014, 18:27"),
- ('time', ast.Datetime(datetime(2012, 4, 30, 13, 19), datetime(2014, 6, 13, 18, 27), True, False)))
-
- def test_equal(self):
- # equal to A
- for editable in [
- # range
- "{predicate} in [{num}:{num}]", "{predicate} : [{num}:{num}]", "{predicate} = [{num}:{num}]",
- ]:
- # positives
- self._test(editable.format(predicate='iso', num=1.23),
- ('iso', ast.Continuous(1.23, 1.23, True, True)))
- # negatives
- self._test(editable.format(predicate='iso', num=-1.23),
- ('iso', ast.Continuous(-1.23, -1.23, True, True)))
-
- for editable in [
- # range
- "{predicate} in [{num}-{num}]", "{predicate} : [{num}-{num}]", "{predicate} = [{num}-{num}]",
- # equation
- "{predicate} = {num}", "{num} = {predicate}",
- ]:
- # positives
- self._test(editable.format(predicate='iso', num=1.23),
- ('iso', ast.Continuous(1.23, 1.23, True, True)))
- # negatives
- self._test(editable.format(predicate='iso', num=-1.23),
- ('iso', ast.Continuous(-1.23, -1.23, True, True)))
- # date
- self._test(editable.format(predicate='time', num="30.04.2012, 13:18"),
- ('time', ast.Datetime(datetime(2012, 4, 30, 13, 18), datetime(2012, 4, 30, 13, 19), True, False)))
-
- def test_dates(self):
- self._test("{predicate} < {num}".format(predicate='time', num="2012"),
- ('time', ast.Datetime(datetime.min, datetime(2012, 1, 1), False, False)))
- self._test("{predicate} < {num}".format(predicate='time', num="2012.04"),
- ('time', ast.Datetime(datetime.min, datetime(2012, 4, 1), False, False)))
- self._test("{predicate} < {num}".format(predicate='time', num="2012.04.30"),
- ('time', ast.Datetime(datetime.min, datetime(2012, 4, 30), False, False)))
- self._test("{predicate} < {num}".format(predicate='time', num="2012.04.30, 3 pm"),
- ('time', ast.Datetime(datetime.min, datetime(2012, 4, 30, 15), False, False)))
- self._test("{predicate} < {num}".format(predicate='time', num="2012.04.30, 15:34"),
- ('time', ast.Datetime(datetime.min, datetime(2012, 4, 30, 15, 34), False, False)))
- self._test("{predicate} < {num}".format(predicate='time', num="2012.04.30, 15:34:12"),
- ('time', ast.Datetime(datetime.min, datetime(2012, 4, 30, 15, 34, 12), False, False)))
- self._test("{predicate} < {num}".format(predicate='time', num="2012.04.30, 15:34:12.98"),
- ('time', ast.Datetime(datetime.min, datetime(2012, 4, 30, 15, 34, 12, 980000), False, False)))
-
- self._test("{predicate} <= {num}".format(predicate='time', num="2012"),
- ('time', ast.Datetime(datetime.min, datetime(2013, 1, 1), False, False)))
- self._test("{predicate} <= {num}".format(predicate='time', num="2012.04"),
- ('time', ast.Datetime(datetime.min, datetime(2012, 5, 1), False, False)))
- self._test("{predicate} <= {num}".format(predicate='time', num="2012.04.30"),
- ('time', ast.Datetime(datetime.min, datetime(2012, 5, 1), False, False)))
- self._test("{predicate} <= {num}".format(predicate='time', num="2012.04.30, 3 pm"),
- ('time', ast.Datetime(datetime.min, datetime(2012, 4, 30, 16), False, False)))
- self._test("{predicate} <= {num}".format(predicate='time', num="2012.04.30, 15:34"),
- ('time', ast.Datetime(datetime.min, datetime(2012, 4, 30, 15, 35), False, False)))
- self._test("{predicate} <= {num}".format(predicate='time', num="2012.04.30, 15:34:12"),
- ('time', ast.Datetime(datetime.min, datetime(2012, 4, 30, 15, 34, 13), False, False)))
- self._test("{predicate} <= {num}".format(predicate='time', num="2012.04.30, 15:34:12.98"),
- ('time', ast.Datetime(datetime.min, datetime(2012, 4, 30, 15, 34, 12, 980001), False, False)))
-
- def test_timerange(self):
- self._test("{predicate} < {num}".format(predicate='time', num="15:34"),
- ('time', ast.TimeRange(datetime.utcfromtimestamp(0.0), datetime(1970, 1, 1, 15, 34), True, False)))
- self._test("{predicate} <= {num}".format(predicate='time', num="15:34"),
- ('time', ast.TimeRange(datetime.utcfromtimestamp(0.0), datetime(1970, 1, 1, 15, 35), True, False)))
- self._test("{predicate} = {num}".format(predicate='time', num="15:34"),
- ('time', ast.TimeRange(datetime(1970, 1, 1, 15, 34), datetime(1970, 1, 1, 15, 35), True, False)))
- self._test("{predicate} > {num}".format(predicate='time', num="15:34"),
- ('time', ast.TimeRange(datetime(1970, 1, 1, 15, 35), datetime(1970, 1, 2), True, True)))
- self._test("{predicate} >= {num}".format(predicate='time', num="15:34"),
- ('time', ast.TimeRange(datetime(1970, 1, 1, 15, 34), datetime(1970, 1, 2), True, True)))
-
- self._test("{numA} <= {predicate} <= {numB}".format(predicate='time', numA="12:34", numB="15:28"),
- ('time', ast.TimeRange(datetime(1970, 1, 1, 12, 34), datetime(1970, 1, 1, 15, 29), True, False)))
- self._test("{numA} <= {predicate} < {numB}".format(predicate='time', numA="12:34", numB="15:28"),
- ('time', ast.TimeRange(datetime(1970, 1, 1, 12, 34), datetime(1970, 1, 1, 15, 28), True, False)))
- self._test("{numA} < {predicate} <= {numB}".format(predicate='time', numA="12:34", numB="15:28"),
- ('time', ast.TimeRange(datetime(1970, 1, 1, 12, 35), datetime(1970, 1, 1, 15, 29), True, False)))
- self._test("{numA} < {predicate} < {numB}".format(predicate='time', numA="12:34", numB="15:28"),
- ('time', ast.TimeRange(datetime(1970, 1, 1, 12, 35), datetime(1970, 1, 1, 15, 28), True, False)))
-
- def test_special(self):
- # special cases: explicit plus sign
- self._test("{predicate} in [+1.23-+4.56]".format(predicate='iso'),
- ('iso', ast.Continuous(1.23, 4.56, True, True)))
- self._test("{predicate} in [-+4.56]".format(predicate='iso'),
- ('iso', ast.Continuous(float('-inf'), 4.56, False, True)))
-
- def test_errors(self):
- # parse errors
- for editable in [
- # equal with exclusive
- "{predicate} in ({num}:{num})", "{predicate} in ({num}-{num})",
- "{predicate} in ({num}:{num}[", "{predicate} in ({num}-{num}[",
- "{predicate} in ]{num}:{num})", "{predicate} in ]{num}-{num})",
- "{predicate} in ]{num}:{num}[", "{predicate} in ]{num}-{num}[",
- # invalid parentesis
- "{predicate} in ){num}:{num}(",
- # misc errors
- # FIXME: Currently all special characters are allowed as categorical value.
- # If this changes, don't forget to enable the tests below.
- #"{predicate} in [{num}{num}]",
- #"{predicate} [{num}:{num}:{num}]",
- #"{predicate} = ({num})",
- #"{predicate} = {num})",
- ]:
- self.assertRaises(errors.ParserError, ast_from_string,
- editable.format(predicate='iso', num=1.23))
-
- for editable in [
- "{predicate} in [{numA}:{numB}]", "{predicate} : [{numA}:{numB}]", "{predicate} = [{numA}:{numB}]",
- "{predicate} in ]{numA}:{numB}]", "{predicate} : ]{numA}:{numB}]", "{predicate} = ]{numA}:{numB}]",
- "{predicate} in [{numA}:{numB}[", "{predicate} : [{numA}:{numB}[", "{predicate} = [{numA}:{numB}[",
- "{predicate} in ({numA}:{numB}]", "{predicate} : ({numA}:{numB}]", "{predicate} = ({numA}:{numB}]",
- "{predicate} in [{numA}:{numB})", "{predicate} : [{numA}:{numB})", "{predicate} = [{numA}:{numB})",
- "{predicate} in ]{numA}:{numB}[", "{predicate} : ]{numA}:{numB}[", "{predicate} = ]{numA}:{numB}[",
- "{predicate} in ]{numA}:{numB})", "{predicate} : ]{numA}:{numB})", "{predicate} = ]{numA}:{numB})",
- "{predicate} in ({numA}:{numB}[", "{predicate} : ({numA}:{numB}[", "{predicate} = ({numA}:{numB}[",
- "{predicate} in ({numA}:{numB})", "{predicate} : ({numA}:{numB})", "{predicate} = ({numA}:{numB})",
- "{numA} < {predicate} < {numB}",
- "{numA} <= {predicate} < {numB}",
- "{numA} < {predicate} <= {numB}",
- ]:
- self.assertRaises(errors.ParserError, ast_from_string,
- editable.format(predicate='iso', numA=4.56, numB=1.23))
- self.assertRaises(errors.ParserError, ast_from_string,
- editable.format(predicate='time', numA="17:35", numB="10:55"))
- self.assertRaises(errors.ParserError, ast_from_string,
- editable.format(predicate='time', numA="18.12.2035", numB="5.7.1999"))
-
- # special cases: empty range with boundary
- self.assertRaises(ParseException, ast_from_string.CONTINUOUS.parseString,
- "{predicate} in [:]".format(predicate='iso'))
- self.assertRaises(ParseException, ast_from_string.CONTINUOUS.parseString,
- "{predicate} in (:[".format(predicate='iso'))
- self.assertRaises(ParseException, ast_from_string.CONTINUOUS.parseString,
- "{predicate} in ]:)".format(predicate='iso'))
- self.assertRaises(ParseException, ast_from_string.CONTINUOUS.parseString,
- "{predicate} in ".format(predicate='iso'))
- # misc
- self.assertRaises(ParseException, ast_from_string.CONTINUOUS.parseString,
- "{predicate} in [{num}{num}]".format(predicate='iso', num=1.23))
- self.assertRaises(ParseException, ast_from_string.CONTINUOUS.parseString,
- "{predicate} [{num}:{num}:{num}]".format(predicate='iso', num=1.23))
- self.assertRaises(ParseException, ast_from_string.CONTINUOUS.parseString,
- "{predicate} = ({num})".format(predicate='iso', num=1.23))
- self.assertRaises(ParseException, ast_from_string.CONTINUOUS.parseString,
- "{predicate} = ({num}".format(predicate='iso', num=1.23), dict(parseAll=True))
- self.assertRaises(ParseException, ast_from_string.CONTINUOUS.parseString,
- "{predicate} = {num})".format(predicate='iso', num=1.23), dict(parseAll=True))
- # range errors
- self.assertRaises(errors.ParserError, ast_from_string, "100 >= iso < 200")
- self.assertRaises(errors.ParserError, ast_from_string, "100 > iso < 200")
- self.assertRaises(errors.ParserError, ast_from_string, "100 > iso <= 200")
- self.assertRaises(errors.ParserError, ast_from_string, "100 >= iso <= 200")
- self.assertRaises(errors.ParserError, ast_from_string, "100 = iso = 200")
- # time/date mixture errors
- self.assertRaises(errors.ParserError, ast_from_string, "12:45 < time < 17.5.2004")
- self.assertRaises(errors.ParserError, ast_from_string, "17.5.2004 < time < 12:45")
- # date/int mixture errors
- self.assertRaises(errors.ParserError, ast_from_string, "17.5.2004 < time < 1245")
- # 1245 is interpreted as the year
- #self.assertRaises(errors.ParserError, ast_from_string, "1245 < time < 17.5.2004")
- # time/int mixture errors
- self.assertRaises(errors.ParserError, ast_from_string, "17:12 < time < 1245")
- self.assertRaises(errors.ParserError, ast_from_string, "1712 < time < 12:45")
-
- # empty query
- self.assertRaises(ParseException, ast_from_string.CONTINUOUS.parseString, "")
-
-
-class TestParseSearch(unittest.TestCase):
- def setUp(self):
- predicates.expose('mime',
- TestScope('attribute', 'mime'), 'Categorical')
- predicates.expose('rank',
- TestScope('attribute', 'rank'), 'Continuous')
- predicates.expose('iso',
- TestScope('attribute', 'iso'), 'Continuous', 'Categorical')
- predicates.expose('time',
- TestScope('generic', 't_image_create_loc'), 'TimeRange', 'Datetime')
- predicates.expose('tag',
- TestScope('generic', 'tag'), 'Categorical')
-
- def test_parse_existence(self):
- self.assertEqual(ast_from_string("has mime"),
- ast.AND([ast.Token('mime', ast.Existence())]))
- self.assertEqual(ast_from_string("has no mime"),
- ast.AND([ast.Token('mime', ast.Inexistence())]))
- self.assertEqual(ast_from_string("has not mime"),
- ast.AND([ast.Token('mime', ast.Inexistence())]))
-
- def test_parse_categorical(self):
- # positive
- self.assertEqual(ast_from_string("iso in 100, 200, 500"),
- ast.AND([ast.Token('iso', ast.SetInclude(['100', '200', '500']))]))
- self.assertEqual(ast_from_string("iso in (100, 200)"),
- ast.AND([ast.Token('iso', ast.SetInclude(['100', '200']))]))
- self.assertEqual(ast_from_string("iso = (100, 200)"),
- ast.AND([ast.Token('iso', ast.SetInclude(['100', '200']))]))
- # FIXME!
- #self.assertEqual(ast_from_string("iso = 100, 200"),
- # ast.AND([ast.Token('iso', ast.SetInclude(['100', '200']))]))
- self.assertEqual(ast_from_string("iso : (100, 200)"),
- ast.AND([ast.Token('iso', ast.SetInclude(['100', '200']))]))
- self.assertEqual(ast_from_string("iso : 100, 200"),
- ast.AND([ast.Token('iso', ast.SetInclude(['100', '200']))]))
- self.assertEqual(ast_from_string("iso:(100,200)"),
- ast.AND([ast.Token('iso', ast.SetInclude(['100', '200']))]))
- self.assertEqual(ast_from_string("iso in (100,200)"),
- ast.AND([ast.Token('iso', ast.SetInclude(['100', '200']))]))
- self.assertEqual(ast_from_string("iso in 100,200"),
- ast.AND([ast.Token('iso', ast.SetInclude(['100', '200']))]))
- self.assertEqual(ast_from_string("iso ~ (100,200)"),
- ast.AND([ast.Token('iso', ast.SetInclude(['100', '200'], approximate=True))]))
- self.assertEqual(ast_from_string("iso ~ 100,200"),
- ast.AND([ast.Token('iso', ast.SetInclude(['100', '200'], approximate=True))]))
-
- # negative
- self.assertEqual(ast_from_string("iso not in 100,200"),
- ast.AND([ast.Token('iso', ast.SetExclude(['100', '200']))]))
- self.assertEqual(ast_from_string("iso not in (100, 200)"),
- ast.AND([ast.Token('iso', ast.SetExclude(['100', '200']))]))
- self.assertEqual(ast_from_string("iso != 100,200"),
- ast.AND([ast.Token('iso', ast.SetExclude(['100', '200']))]))
- self.assertEqual(ast_from_string("iso != (100, 200)"),
- ast.AND([ast.Token('iso', ast.SetExclude(['100', '200']))]))
- self.assertEqual(ast_from_string("iso !~ 100,200"),
- ast.AND([ast.Token('iso', ast.SetExclude(['100', '200'], approximate=True))]))
- self.assertEqual(ast_from_string("iso !~ (100, 200)"),
- ast.AND([ast.Token('iso', ast.SetExclude(['100', '200'], approximate=True))]))
-
- # one value
- self.assertEqual(ast_from_string("mime : text"),
- ast.AND([ast.Token('mime', ast.SetInclude(['text']))]))
- self.assertEqual(ast_from_string("mime in text"),
- ast.AND([ast.Token('mime', ast.SetInclude(['text']))]))
- self.assertEqual(ast_from_string("mime = text"),
- ast.AND([ast.Token('mime', ast.SetInclude(['text']))]))
- self.assertEqual(ast_from_string("mime ~ text"),
- ast.AND([ast.Token('mime', ast.SetInclude(['text'], approximate=True))]))
- self.assertEqual(ast_from_string("mime != text"),
- ast.AND([ast.Token('mime', ast.SetExclude(['text']))]))
- self.assertEqual(ast_from_string("mime not in text"),
- ast.AND([ast.Token('mime', ast.SetExclude(['text']))]))
- self.assertEqual(ast_from_string("mime !~ text"),
- ast.AND([ast.Token('mime', ast.SetExclude(['text'], approximate=True))]))
-
- # expressions with slash and comma
- self.assertEqual(ast_from_string('mime : "text"'),
- ast.AND([ast.Token('mime', ast.SetInclude(['text']))]))
- self.assertEqual(ast_from_string('mime : "text", "plain"'),
- ast.AND([ast.Token('mime', ast.SetInclude(['text', 'plain']))]))
- self.assertEqual(ast_from_string('mime : "text, plain"'),
- ast.AND([ast.Token('mime', ast.SetInclude(['text, plain']))]))
- self.assertEqual(ast_from_string('mime ~ "text/plain"'),
- ast.AND([ast.Token('mime', ast.SetInclude(['text/plain'], approximate=True))]))
- self.assertEqual(ast_from_string('mime = ("text/plain", "image/jpeg")'),
- ast.AND([ast.Token('mime', ast.SetInclude(['text/plain', 'image/jpeg']))]))
-
- def test_parse_tag(self):
-
- # only tag: tag, tags, (tag), (tags)
- self.assertEqual(ast_from_string("foo"),
- ast.AND([ast.Token('tag', ast.SetInclude(['foo']))]))
- self.assertEqual(ast_from_string("(foo)"),
- ast.AND([ast.Token('tag', ast.SetInclude(['foo']))]))
- self.assertEqual(ast_from_string("foo, bar"),
- ast.AND([ast.Token('tag', ast.SetInclude(['foo', 'bar']))]))
- self.assertEqual(ast_from_string("foo,bar"),
- ast.AND([ast.Token('tag', ast.SetInclude(['foo', 'bar']))]))
- self.assertEqual(ast_from_string("(foo, bar,foobar)"),
- ast.AND([ast.Token('tag', ast.SetInclude(['foo', 'bar', 'foobar']))]))
-
- # op and tag: !tag, ~tag, !~tag
- self.assertEqual(ast_from_string("~foo"),
- ast.AND([ast.Token('tag', ast.SetInclude(['foo'], approximate=True))]))
- self.assertEqual(ast_from_string("~ foo"),
- ast.AND([ast.Token('tag', ast.SetInclude(['foo'], approximate=True))]))
- self.assertEqual(ast_from_string("!foo"),
- ast.AND([ast.Token('tag', ast.SetExclude(['foo']))]))
- self.assertEqual(ast_from_string("! foo"),
- ast.AND([ast.Token('tag', ast.SetExclude(['foo']))]))
- self.assertEqual(ast_from_string("!~foo"),
- ast.AND([ast.Token('tag', ast.SetExclude(['foo'], approximate=True))]))
- self.assertEqual(ast_from_string("!~ foo"),
- ast.AND([ast.Token('tag', ast.SetExclude(['foo'], approximate=True))]))
-
- # op and list: ! (tags), ~tags, ...
- self.assertEqual(ast_from_string("~ foo, bar"),
- ast.AND([ast.Token('tag', ast.SetInclude(['foo', 'bar'], approximate=True))]))
- self.assertEqual(ast_from_string("~foo, bar"),
- ast.AND([ast.Token('tag', ast.SetInclude(['foo', 'bar'], approximate=True))]))
- self.assertEqual(ast_from_string("~ (foo, bar)"),
- ast.AND([ast.Token('tag', ast.SetInclude(['foo', 'bar'], approximate=True))]))
- self.assertEqual(ast_from_string("! foo, bar"),
- ast.AND([ast.Token('tag', ast.SetExclude(['foo', 'bar']))]))
- self.assertEqual(ast_from_string("! (foo, bar)"),
- ast.AND([ast.Token('tag', ast.SetExclude(['foo', 'bar']))]))
- self.assertEqual(ast_from_string("! (foo,bar)"),
- ast.AND([ast.Token('tag', ast.SetExclude(['foo', 'bar']))]))
- self.assertEqual(ast_from_string("!~ foo, bar"),
- ast.AND([ast.Token('tag', ast.SetExclude(['foo', 'bar'], approximate=True))]))
- self.assertEqual(ast_from_string("!~ (foo, bar)"),
- ast.AND([ast.Token('tag', ast.SetExclude(['foo', 'bar'], approximate=True))]))
- self.assertEqual(ast_from_string("!~(foo,bar)"),
- ast.AND([ast.Token('tag', ast.SetExclude(['foo', 'bar'], approximate=True))]))
-
- def test_parse_query(self):
- # simple query
- self.assertEqual(ast_from_string('foo / bar'), ast.AND([
- ast.Token('tag', ast.SetInclude('foo')),
- ast.Token('tag', ast.SetInclude('bar'))]))
- self.assertEqual(ast_from_string('iso in ("foo", "bar") / mime = plain'), ast.AND([
- ast.Token('iso', ast.SetInclude('foo', 'bar')),
- ast.Token('mime', ast.SetInclude('plain'))]))
- self.assertEqual(ast_from_string('iso in ("foo", "bar") / mime = plain'), ast.AND([
- ast.Token('iso', ast.SetInclude('foo', 'bar')),
- ast.Token('mime', ast.SetInclude('plain'))]))
- self.assertEqual(ast_from_string('iso = 1.23 / rank < 5'), ast.AND([
- ast.Token('iso', ast.Continuous(1.23, 1.23, True, True)),
- ast.Token('rank', ast.Continuous(hi=5))]))
- self.assertEqual(ast_from_string('time >= 12:50 / time < 13:50'), ast.AND([
- ast.Token('time', ast.TimeRange(lo=datetime(1970, 1, 1, 12, 50), lo_inc=True, hi_inc=True)),
- ast.Token('time', ast.TimeRange(hi=datetime(1970, 1, 1, 13, 50), lo_inc=True, hi_inc=False))]))
- self.assertEqual(ast_from_string('time >= 17.5.2001 / time < 18.4.2002'), ast.AND([
- ast.Token('time', ast.Datetime(lo=datetime(2001, 5, 17, 0, 0), lo_inc=True)),
- ast.Token('time', ast.Datetime(hi=datetime(2002, 4, 18, 0, 0)))]))
- # mixing expressions
- self.assertEqual(ast_from_string('foo / iso in "bar" / mime ~ "text/plain" / iso < 100 / time >= 17.5.2001 / time < 13:50'), ast.AND([
- ast.Token('tag', ast.SetInclude('foo')),
- ast.Token('iso', ast.SetInclude('bar')),
- ast.Token('mime', ast.SetInclude('text/plain', approximate=True)),
- ast.Token('iso', ast.Continuous(hi=100)),
- ast.Token('time', ast.Datetime(lo=datetime(2001, 5, 17, 0, 0), lo_inc=True)),
- ast.Token('time', ast.TimeRange(hi=datetime(1970, 1, 1, 13, 50), lo_inc=True))]))
-
- # leading/trailing slashes
- self.assertRaises(errors.ParserError, ast_from_string, '/ foobar')
- self.assertRaises(errors.ParserError, ast_from_string, 'foobar /')
- self.assertRaises(errors.ParserError, ast_from_string, 'foobar / ')
- self.assertRaises(errors.ParserError, ast_from_string, 'foo // bar')
- self.assertRaises(errors.ParserError, ast_from_string, 'foo / / bar')
-
- def test_quoting(self):
- self.assertEqual(ast_from_string("tag in ('(foo, bar)', foobar)"),
- ast.AND([ast.Token('tag', ast.SetInclude(['(foo, bar)', 'foobar']))]))
- self.assertEqual(ast_from_string('tag in ("(foo, bar)", foobar)'),
- ast.AND([ast.Token('tag', ast.SetInclude(['(foo, bar)', 'foobar']))]))
- self.assertEqual(ast_from_string('tag in ("(foo, \\"bar\\")", foobar)'),
- ast.AND([ast.Token('tag', ast.SetInclude(['(foo, "bar")', 'foobar']))]))
- self.assertEqual(ast_from_string('tag in ("(foo, bar)", "foobar")'),
- ast.AND([ast.Token('tag', ast.SetInclude(['(foo, bar)', 'foobar']))]))
- self.assertEqual(ast_from_string('tag in ("(foo, bar)", \'foobar\')'),
- ast.AND([ast.Token('tag', ast.SetInclude(['(foo, bar)', 'foobar']))]))
-
- # error cases
- self.assertRaises(errors.ParserError, ast_from_string, ('tag in ("(foo, bar, foobar)'))
- self.assertRaises(errors.ParserError, ast_from_string, ("tag in ('(foo, bar, foobar)"))
-
-
-## main ##
-
-if __name__ == '__main__':
- unittest.main()
-
-## EOF ##