aboutsummaryrefslogtreecommitdiffstats
path: root/test/query/test_validator.py
diff options
context:
space:
mode:
authorMatthias Baumgartner <dev@igsor.net>2023-03-05 19:25:29 +0100
committerMatthias Baumgartner <dev@igsor.net>2023-03-05 19:25:29 +0100
commit48b6081d0092e9c5a1b0ad79bdde2e51649bf61a (patch)
tree634198c34aae3c0306ce30ac7452abd7b53a14e8 /test/query/test_validator.py
parent91437ba89d35bf482f3d9671bb99ef2fc69f5985 (diff)
parente4845c627e97a6d125bf33d9e7a4a8d373d7fc4a (diff)
downloadbsfs-bf79057349a8fc842c660c0ed17599ceb5f285ca.tar.gz
bsfs-bf79057349a8fc842c660c0ed17599ceb5f285ca.tar.bz2
bsfs-bf79057349a8fc842c660c0ed17599ceb5f285ca.zip
Merge branch 'develop'v0.23.03
Diffstat (limited to 'test/query/test_validator.py')
-rw-r--r--test/query/test_validator.py505
1 files changed, 505 insertions, 0 deletions
diff --git a/test/query/test_validator.py b/test/query/test_validator.py
new file mode 100644
index 0000000..418463e
--- /dev/null
+++ b/test/query/test_validator.py
@@ -0,0 +1,505 @@
+
+# imports
+import unittest
+
+# bsfs imports
+from bsfs import schema as _schema
+from bsfs.namespace import ns
+from bsfs.query import ast
+from bsfs.utils import errors
+
+# objects to test
+from bsfs.query.validator import Filter, Fetch
+
+
+## code ##
+
+ns.bse = ns.bsfs.Entity()
+
+class TestFilter(unittest.TestCase):
+ def setUp(self):
+ self.schema = _schema.from_string('''
+ prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
+ prefix xsd: <http://www.w3.org/2001/XMLSchema#>
+
+ prefix bsfs: <https://schema.bsfs.io/core/>
+ prefix bse: <https://schema.bsfs.io/core/Entity#>
+ prefix bsl: <https://schema.bsfs.io/core/Literal/>
+
+ bsfs:Entity rdfs:subClassOf bsfs:Node .
+ bsfs:URI rdfs:subClassOf bsfs:Literal .
+
+ bsfs:Tag rdfs:subClassOf bsfs:Node .
+ xsd:string rdfs:subClassOf bsfs:Literal .
+ bsl:Number rdfs:subClassOf bsfs:Literal .
+ bsl:Array rdfs:subClassOf bsfs:Literal .
+ <https://schema.bsfs.io/core/Literal/Array/Feature> rdfs:subClassOf bsl:Array .
+ xsd:integer rdfs:subClassOf bsl:Number .
+
+ bsfs:Colors rdfs:subClassOf <https://schema.bsfs.io/core/Literal/Array/Feature> ;
+ bsfs:dimension "5"^^xsd:integer ;
+ bsfs:dtype bsfs:f32 .
+
+ bse:color rdfs:subClassOf bsfs:Predicate ;
+ rdfs:domain bsfs:Node ;
+ rdfs:range bsfs:Colors ;
+ bsfs:unique "true"^^xsd:boolean .
+
+ bse:comment rdfs:subClassOf bsfs:Predicate ;
+ rdfs:domain bsfs:Node ;
+ rdfs:range xsd:string ;
+ bsfs:unique "false"^^xsd:boolean .
+
+ bse:filesize rdfs:subClassOf bsfs:Predicate ;
+ rdfs:domain bsfs:Entity ;
+ rdfs:range xsd:integer ;
+ 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:label rdfs:subClassOf bsfs:Predicate ;
+ rdfs:domain bsfs:Tag ;
+ rdfs:range xsd:string ;
+ bsfs:unique "true"^^xsd:boolean .
+
+ bse:buddy rdfs:subClassOf bsfs:Predicate ;
+ rdfs:domain bsfs:Entity ;
+ rdfs:range bsfs:Node ;
+ bsfs:unique "false"^^xsd:boolean .
+
+ ''')
+ self.validate = Filter(self.schema)
+
+ def test_call(self): # tests validate implicitly
+ # root_type must be a _schema.Node
+ self.assertRaises(TypeError, self.validate, 1234, None)
+ self.assertRaises(TypeError, self.validate, '1234', None)
+ self.assertRaises(TypeError, self.validate, self.schema.literal(ns.bsfs.URI), None)
+ # root_type must exist in the schema
+ self.assertRaises(errors.ConsistencyError, self.validate, self.schema.node(ns.bsfs.Node).child(ns.bsfs.Image), None)
+ self.assertRaises(errors.ConsistencyError, self.validate, self.schema.node(ns.bsfs.Entity).child(ns.bsfs.Image), None)
+ # valid query returns true
+ self.assertTrue(self.validate(self.schema.node(ns.bsfs.Entity),
+ ast.filter.Any(ast.filter.OneOf(ns.bse.tag, ns.bse.buddy),
+ ast.filter.Or(
+ ast.filter.Is('http://example.com/symbol#1234'),
+ ast.filter.All(ns.bse.comment, ast.filter.StartsWith('foo')),
+ ast.filter.And(
+ ast.filter.Has(ns.bse.comment, ast.filter.Or(
+ ast.filter.GreaterThan(5),
+ ast.filter.LessThan(1),
+ )
+ ),
+ ast.filter.Not(ast.filter.Any(ns.bse.comment,
+ ast.filter.Not(ast.filter.Equals('hello world')))),
+ ast.filter.Any(ns.bse.color, ast.filter.Distance([1,2,3,4,5], 3)),
+ )))))
+ # invalid paths raise consistency error
+ self.assertRaises(errors.ConsistencyError, self.validate, self.schema.node(ns.bsfs.Entity),
+ ast.filter.Any(ast.filter.OneOf(ns.bse.tag, ns.bse.buddy),
+ ast.filter.Or(
+ ast.filter.All(ns.bse.comment, ast.filter.Equals('hello world')),
+ ast.filter.All(ns.bse.label, ast.filter.Equals('hello world')), # domain mismatch
+ )))
+
+ def test_routing(self):
+ self.assertRaises(errors.BackendError, self.validate._parse_filter_expression, ast.filter.FilterExpression(), self.schema.node(ns.bsfs.Node))
+ self.assertRaises(errors.BackendError, self.validate._parse_predicate_expression, ast.filter.PredicateExpression())
+
+ def test_predicate(self):
+ # predicate must be in the schema
+ self.assertRaises(errors.ConsistencyError, self.validate._predicate, ast.filter.Predicate(ns.bse.invalid))
+ # predicate must have a range
+ self.assertRaises(errors.BackendError, self.validate._predicate, ast.filter.Predicate(ns.bsfs.Predicate))
+ # predicate returns domain and range
+ self.assertEqual(self.validate._predicate(ast.filter.Predicate(ns.bse.tag)),
+ (self.schema.node(ns.bsfs.Entity), self.schema.node(ns.bsfs.Tag)))
+ # reverse is applied
+ self.assertEqual(self.validate._predicate(ast.filter.Predicate(ns.bse.tag, reverse=True)),
+ (self.schema.node(ns.bsfs.Tag), self.schema.node(ns.bsfs.Entity)))
+
+ def test_one_of(self):
+ # domains must both be nodes or literals
+ self.assertRaises(errors.ConsistencyError, self.validate._one_of, ast.filter.OneOf(ns.bse.tag, ast.filter.Predicate(ns.bse.label, reverse=True)))
+ # domains must be related
+ self.assertRaises(errors.ConsistencyError, self.validate._one_of, ast.filter.OneOf(ns.bse.tag, ns.bse.label))
+ # ranges must both be nodes or literals
+ self.assertRaises(errors.ConsistencyError, self.validate._one_of, ast.filter.OneOf(ns.bse.tag, ns.bse.comment))
+ # ranges must be related
+ self.assertRaises(errors.ConsistencyError, self.validate._one_of, ast.filter.OneOf(ns.bse.tag, ast.filter.Predicate(ns.bse.buddy, reverse=True)))
+ # one_of returns most specific domain
+ self.assertEqual(self.validate._one_of(ast.filter.OneOf(ns.bse.comment, ns.bse.label)),
+ (self.schema.node(ns.bsfs.Tag), self.schema.literal(ns.xsd.string)))
+ # one_of returns the most generic range
+ self.assertEqual(self.validate._one_of(ast.filter.OneOf(ns.bse.tag, ns.bse.buddy)),
+ (self.schema.node(ns.bsfs.Entity), self.schema.node(ns.bsfs.Node)))
+
+ def test_branch(self):
+ # type must be a node
+ self.assertRaises(errors.ConsistencyError, self.validate._branch, self.schema.literal(ns.bsfs.Literal), None)
+ # type must be in the schema
+ self.assertRaises(errors.ConsistencyError, self.validate._branch, self.schema.node(ns.bsfs.Node).child(ns.bsfs.Invalid), None)
+ # predicate is verified
+ self.assertRaises(errors.ConsistencyError, self.validate._branch, self.schema.node(ns.bsfs.Entity),
+ ast.filter.Any(ns.bsfs.Invalid, ast.filter.Is('http://example.com/entity#1234')))
+ # predicate must match the domain
+ self.assertRaises(errors.ConsistencyError, self.validate._branch, self.schema.node(ns.bsfs.Node),
+ ast.filter.Any(ns.bse.tag, ast.filter.Is('http://example.com/tag#1234')))
+ self.assertRaises(errors.ConsistencyError, self.validate._branch, self.schema.node(ns.bsfs.Tag),
+ ast.filter.Any(ns.bse.tag, ast.filter.Is('http://example.com/tag#1234')))
+ # child expression must be valid
+ self.assertRaises(errors.ConsistencyError, self.validate._branch, self.schema.node(ns.bsfs.Entity),
+ ast.filter.Any(ns.bse.tag, ast.filter.Equals('hello world')))
+ # branch accepts valid expressions
+ self.assertIsNone(self.validate._branch(self.schema.node(ns.bsfs.Entity),
+ ast.filter.Any(ns.bse.tag, ast.filter.Is('http://example.com/entity#1234'))))
+ self.assertIsNone(self.validate._branch(self.schema.node(ns.bsfs.Entity),
+ ast.filter.All(ns.bse.tag, ast.filter.Is('http://example.com/entity#1234'))))
+
+ def test_agg(self):
+ # agg evaluates child expressions
+ self.assertRaises(errors.ConsistencyError, self.validate._agg, self.schema.node(ns.bsfs.Entity),
+ ast.filter.And(ast.filter.Is('http://example.com/entity#1234'), ast.filter.Equals('hello world')))
+ self.assertRaises(errors.ConsistencyError, self.validate._agg, self.schema.literal(ns.xsd.string),
+ ast.filter.And(ast.filter.Is('http://example.com/entity#1234'), ast.filter.Equals('hello world')))
+ self.assertRaises(errors.ConsistencyError, self.validate._agg, self.schema.node(ns.bsfs.Entity),
+ ast.filter.Or(ast.filter.Is('http://example.com/entity#1234'), ast.filter.Equals('hello world')))
+ self.assertRaises(errors.ConsistencyError, self.validate._agg, self.schema.literal(ns.xsd.string),
+ ast.filter.Or(ast.filter.Is('http://example.com/entity#1234'), ast.filter.Equals('hello world')))
+ # agg works on nodes
+ self.assertIsNone(self.validate._agg(self.schema.node(ns.bsfs.Entity),
+ ast.filter.And(ast.filter.Is('http://example.com/entity#1234'), ast.filter.Is('http://example.com/entity#4321'))))
+ self.assertIsNone(self.validate._agg(self.schema.node(ns.bsfs.Entity),
+ ast.filter.Or(ast.filter.Is('http://example.com/entity#1234'), ast.filter.Is('http://example.com/entity#4321'))))
+ # agg works on literals
+ self.assertIsNone(self.validate._agg(self.schema.literal(ns.xsd.string),
+ ast.filter.And(ast.filter.Equals('foobar'), ast.filter.Equals('hello world'))))
+ self.assertIsNone(self.validate._agg(self.schema.literal(ns.xsd.string),
+ ast.filter.Or(ast.filter.Equals('foobar'), ast.filter.Equals('hello world'))))
+
+ def test_not(self):
+ # not evaluates child expressions
+ self.assertRaises(errors.ConsistencyError, self.validate._not, self.schema.node(ns.bsfs.Entity),
+ ast.filter.Not(ast.filter.Equals('hello world')))
+ self.assertRaises(errors.ConsistencyError, self.validate._not, self.schema.literal(ns.xsd.string),
+ ast.filter.Not(ast.filter.Is('http://example.com/entity#1234')))
+ # not works on nodes
+ self.assertIsNone(self.validate._not(self.schema.node(ns.bsfs.Entity),
+ ast.filter.Not(ast.filter.Is('http://example.com/entity#1234'))))
+ # not works on literals
+ self.assertIsNone(self.validate._not(self.schema.literal(ns.xsd.string),
+ ast.filter.Not(ast.filter.Equals('hello world'))))
+
+ def test_has(self):
+ # type must be node
+ self.assertRaises(errors.ConsistencyError, self.validate._has, self.schema.literal(ns.bsfs.Literal),
+ ast.filter.Has(ns.bse.tag))
+ # type must be in the schema
+ self.assertRaises(errors.ConsistencyError, self.validate._has, self.schema.node(ns.bsfs.Node).child(ns.bsfs.Invalid),
+ ast.filter.Has(ns.bse.tag))
+ # has checks predicate
+ self.assertRaises(errors.ConsistencyError, self.validate._has, self.schema.node(ns.bsfs.Entity),
+ ast.filter.Has(ns.bse.invalid))
+ # predicate must match domain
+ self.assertRaises(errors.ConsistencyError, self.validate._has, self.schema.node(ns.bsfs.Tag),
+ ast.filter.Has(ns.bse.tag))
+ # has checks count expression
+ self.assertRaises(errors.ConsistencyError, self.validate._has, self.schema.node(ns.bsfs.Entity),
+ ast.filter.Has(ns.bse.tag, ast.filter.Is('http://example.com/entity#1234')))
+ # has accepts correct expressions
+ self.assertIsNone(self.validate._has(self.schema.node(ns.bsfs.Entity), ast.filter.Has(ns.bse.tag, ast.filter.GreaterThan(5))))
+
+ def test_is(self):
+ # type must be node
+ self.assertRaises(errors.ConsistencyError, self.validate._is, self.schema.literal(ns.bsfs.Literal),
+ ast.filter.Is('http://example.com/foo'))
+ # type must be in the schema
+ self.assertRaises(errors.ConsistencyError, self.validate._is, self.schema.node(ns.bsfs.Node).child(ns.bsfs.Invalid),
+ ast.filter.Is('http://example.com/foo'))
+ # is accepts correct expressions
+ self.assertIsNone(self.validate._is(self.schema.node(ns.bsfs.Entity), ast.filter.Is('http://example.com/entity#1234')))
+
+ def test_value(self):
+ # type must be literal
+ self.assertRaises(errors.ConsistencyError, self.validate._value, self.schema.node(ns.bsfs.Node),
+ ast.filter.Equals('hello world'))
+ self.assertRaises(errors.ConsistencyError, self.validate._value, self.schema.node(ns.bsfs.Node),
+ ast.filter.Substring('hello world'))
+ self.assertRaises(errors.ConsistencyError, self.validate._value, self.schema.node(ns.bsfs.Node),
+ ast.filter.StartsWith('hello world'))
+ self.assertRaises(errors.ConsistencyError, self.validate._value, self.schema.node(ns.bsfs.Node),
+ ast.filter.EndsWith('hello world'))
+ # type must be in the schema
+ self.assertRaises(errors.ConsistencyError, self.validate._value, self.schema.literal(ns.bsfs.Literal).child(ns.bsfs.Invalid),
+ ast.filter.Equals('hello world'))
+ self.assertRaises(errors.ConsistencyError, self.validate._value, self.schema.literal(ns.bsfs.Literal).child(ns.bsfs.Invalid),
+ ast.filter.Substring('hello world'))
+ self.assertRaises(errors.ConsistencyError, self.validate._value, self.schema.literal(ns.bsfs.Literal).child(ns.bsfs.Invalid),
+ ast.filter.StartsWith('hello world'))
+ self.assertRaises(errors.ConsistencyError, self.validate._value, self.schema.literal(ns.bsfs.Literal).child(ns.bsfs.Invalid),
+ ast.filter.EndsWith('hello world'))
+ # value accepts correct expressions
+ self.assertIsNone(self.validate._value(self.schema.literal(ns.xsd.string), ast.filter.Equals('hello world')))
+ self.assertIsNone(self.validate._value(self.schema.literal(ns.xsd.string), ast.filter.Substring('hello world')))
+ self.assertIsNone(self.validate._value(self.schema.literal(ns.xsd.string), ast.filter.StartsWith('hello world')))
+ self.assertIsNone(self.validate._value(self.schema.literal(ns.xsd.string), ast.filter.EndsWith('hello world')))
+
+ def test_bounded(self):
+ # type must be literal
+ self.assertRaises(errors.ConsistencyError, self.validate._bounded, self.schema.node(ns.bsfs.Node),
+ ast.filter.GreaterThan(0))
+ self.assertRaises(errors.ConsistencyError, self.validate._bounded, self.schema.node(ns.bsfs.Node),
+ ast.filter.LessThan(0))
+ # type must be in the schema
+ self.assertRaises(errors.ConsistencyError, self.validate._bounded, self.schema.literal(ns.bsfs.Literal).child(ns.bsfs.Invalid),
+ ast.filter.GreaterThan(0))
+ self.assertRaises(errors.ConsistencyError, self.validate._bounded, self.schema.literal(ns.bsfs.Literal).child(ns.bsfs.Invalid),
+ ast.filter.LessThan(0))
+ # type must be a number
+ self.assertRaises(errors.ConsistencyError, self.validate._bounded, self.schema.literal(ns.xsd.string),
+ ast.filter.LessThan(0))
+ # bounded accepts correct expressions
+ self.assertIsNone(self.validate._bounded(self.schema.literal(ns.xsd.integer), ast.filter.LessThan(0)))
+ self.assertIsNone(self.validate._bounded(self.schema.literal(ns.xsd.integer), ast.filter.GreaterThan(0)))
+
+ def test_distance(self):
+ # type must be a literal
+ self.assertRaises(errors.ConsistencyError, self.validate._distance, self.schema.node(ns.bsfs.Node),
+ ast.filter.Distance([1,2,3], 1, False))
+ # type must be a feature
+ self.assertRaises(errors.ConsistencyError, self.validate._distance, self.schema.literal(ns.bsl.Array),
+ ast.filter.Distance([1,2,3], 1, False))
+ # type must be in the schema
+ self.assertRaises(errors.ConsistencyError, self.validate._distance, self.schema.literal(ns.bsl.Array.Feature).child(ns.bsfs.Invalid),
+ ast.filter.Distance([1,2,3], 1, False))
+ # FIXME: reference must be a numpy array
+ # reference must have the correct dimension
+ self.assertRaises(errors.ConsistencyError, self.validate._distance, self.schema.literal(ns.bsfs.Colors),
+ ast.filter.Distance([1,2,3], 1, False))
+ # FIXME: reference must have the correct dtype
+ # distance accepts correct expressions
+ self.assertIsNone(self.validate._distance(self.schema.literal(ns.bsfs.Colors), ast.filter.Distance([1,2,3,4,5], 1, False)))
+
+
+class TestFetch(unittest.TestCase):
+ def setUp(self):
+ self.schema = _schema.from_string('''
+ prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
+ prefix xsd: <http://www.w3.org/2001/XMLSchema#>
+
+ prefix bsfs: <https://schema.bsfs.io/core/>
+ prefix bse: <https://schema.bsfs.io/core/Entity#>
+
+ bsfs:Entity rdfs:subClassOf bsfs:Node .
+ bsfs:Tag rdfs:subClassOf bsfs:Node .
+ xsd:string rdfs:subClassOf bsfs:Literal .
+
+ bse:filename rdfs:subClassOf bsfs:Predicate ;
+ rdfs:domain bsfs:Node ;
+ rdfs:range xsd:string .
+
+ bse:tag rdfs:subClassOf bsfs:Predicate ;
+ rdfs:domain bsfs:Entity ;
+ rdfs:range bsfs:Tag .
+
+ bse:label rdfs:subClassOf bsfs:Predicate ;
+ rdfs:domain bsfs:Tag ;
+ rdfs:range xsd:string .
+
+ ''')
+ self.validate = Fetch(self.schema)
+
+ def test_call(self): # tests validate implicitly
+ # call accepts correct expressions
+ self.assertTrue(self.validate(self.schema.node(ns.bsfs.Entity),
+ ast.fetch.Fetch(ns.bse.tag, ast.fetch.Value(ns.bse.label, 'value'))))
+ self.assertTrue(self.validate(self.schema.node(ns.bsfs.Entity),
+ ast.fetch.Fetch(ns.bse.tag, ast.fetch.This('this'))))
+ self.assertTrue(self.validate(self.schema.node(ns.bsfs.Entity),
+ ast.fetch.This('this')))
+ self.assertTrue(self.validate(self.schema.node(ns.bsfs.Entity),
+ ast.fetch.All(ast.fetch.This('this'), ast.fetch.Node(ns.bse.tag, 'node'), ast.fetch.Value(ns.bse.filename, 'value'))))
+ # type must be a Node
+ self.assertRaises(TypeError, self.validate, 1234, ast.fetch.This('this'))
+ self.assertRaises(TypeError, self.validate, 'foobar', ast.fetch.This('this'))
+ self.assertRaises(TypeError, self.validate, self.schema.literal(ns.bsfs.Literal), ast.fetch.This('this'))
+ # type must be in the schema
+ self.assertRaises(errors.ConsistencyError, self.validate, self.schema.node(ns.bsfs.Node).child(ns.bsfs.Invalid),
+ ast.fetch.FetchExpression())
+ # expression must be a fetch expression
+ self.assertRaises(TypeError, self.validate, self.schema.node(ns.bsfs.Entity), 1234)
+ self.assertRaises(TypeError, self.validate, self.schema.node(ns.bsfs.Entity), 'hello')
+ self.assertRaises(TypeError, self.validate, self.schema.node(ns.bsfs.Entity), ast.filter.FilterExpression())
+ # expression must be valid
+ self.assertRaises(errors.ConsistencyError, self.validate, self.schema.node(ns.bsfs.Entity),
+ ast.fetch.Fetch(ns.bse.tag, ast.fetch.Node(ns.bse.label, 'node')))
+ self.assertRaises(errors.ConsistencyError, self.validate, self.schema.node(ns.bsfs.Entity),
+ ast.fetch.Value(ns.bse.tag, 'value'))
+
+ def test_routing(self):
+ # Node passes _branch, _named, and _node checks
+ self.assertRaises(errors.ConsistencyError, self.validate._parse_fetch_expression, self.schema.node(ns.bsfs.Node),
+ ast.fetch.Node(ns.bse.tag, 'node')) # fails in _branch
+ self.assertRaises(errors.BackendError, self.validate._parse_fetch_expression, self.schema.node(ns.bsfs.Entity),
+ ast.fetch.Node(ns.bse.tag, '')) # fails in _named
+ self.assertRaises(errors.ConsistencyError, self.validate._parse_fetch_expression, self.schema.node(ns.bsfs.Entity),
+ ast.fetch.Node(ns.bse.label, 'node')) # fails in _node
+ # Value passes _branch, _named, and _value checks
+ self.assertRaises(errors.ConsistencyError, self.validate._parse_fetch_expression, self.schema.node(ns.bsfs.Node),
+ ast.fetch.Value(ns.bse.label, 'value')) # fails in _branch
+ self.assertRaises(errors.BackendError, self.validate._parse_fetch_expression, self.schema.node(ns.bsfs.Entity),
+ ast.fetch.Value(ns.bse.filename, '')) # fails in _named
+ self.assertRaises(errors.ConsistencyError, self.validate._parse_fetch_expression, self.schema.node(ns.bsfs.Entity),
+ ast.fetch.Value(ns.bse.tag, 'value')) # fails in _value
+ # Fetch passes _branch and _fetch checks
+ self.assertRaises(errors.ConsistencyError, self.validate._parse_fetch_expression, self.schema.node(ns.bsfs.Node),
+ ast.fetch.Fetch(ns.bse.tag, ast.fetch.This('this'))) # fails in _branch
+ self.assertRaises(errors.ConsistencyError, self.validate._parse_fetch_expression, self.schema.node(ns.bsfs.Node),
+ ast.fetch.Fetch(ns.bse.filename, ast.fetch.This('this'))) # fails in _fetch
+ # invalid expressions cannot be parsed
+ type_ = self.schema.node(ns.bsfs.Node)
+ self.assertRaises(errors.BackendError, self.validate._parse_fetch_expression, type_,
+ ast.filter.FilterExpression())
+ self.assertRaises(errors.BackendError, self.validate._parse_fetch_expression, type_,
+ 1234)
+ self.assertRaises(errors.BackendError, self.validate._parse_fetch_expression, type_,
+ 'hello world')
+
+ def test_all(self):
+ # all accepts correct expressions
+ self.assertIsNone(self.validate._all(self.schema.node(ns.bsfs.Entity),
+ ast.fetch.All(ast.fetch.Value(ns.bse.filename, 'value'), ast.fetch.Node(ns.bse.tag, 'node'))))
+ # child expressions must be valid
+ self.assertRaises(errors.ConsistencyError, self.validate._all, self.schema.node(ns.bsfs.Entity),
+ ast.fetch.All(ast.fetch.Value(ns.bse.tag, 'value')))
+ self.assertRaises(errors.ConsistencyError, self.validate._all, self.schema.node(ns.bsfs.Entity),
+ ast.fetch.All(ast.fetch.Value(ns.bse.filename, 'value'), ast.fetch.Node(ns.bse.filename, 'node')))
+ self.assertRaises(errors.ConsistencyError, self.validate._all, self.schema.node(ns.bsfs.Entity),
+ ast.fetch.All(ast.fetch.Value(ns.bse.tag, 'value'), ast.fetch.Node(ns.bse.tag, 'node')))
+ self.assertRaises(errors.ConsistencyError, self.validate._all, self.schema.node(ns.bsfs.Entity),
+ ast.fetch.All(ast.fetch.Value(ns.bse.tag, 'value'), ast.fetch.Node(ns.bse.filename, 'node')))
+
+ def test_branch(self):
+ # branch accepts correct expressions
+ self.assertIsNone(self.validate._branch(self.schema.node(ns.bsfs.Entity),
+ ast.fetch._Branch(ns.bse.filename)))
+ self.assertIsNone(self.validate._branch(self.schema.node(ns.bsfs.Entity),
+ ast.fetch.Fetch(ns.bse.tag, ast.fetch.This('this'))))
+ self.assertIsNone(self.validate._branch(self.schema.node(ns.bsfs.Entity),
+ ast.fetch.Value(ns.bse.filename, 'value')))
+ self.assertIsNone(self.validate._branch(self.schema.node(ns.bsfs.Entity),
+ ast.fetch.Node(ns.bse.tag, 'node')))
+ # type must be a node
+ self.assertRaises(errors.ConsistencyError, self.validate._branch, self.schema.literal(ns.bsfs.Literal),
+ ast.fetch._Branch(ns.bse.filename))
+ self.assertRaises(errors.ConsistencyError, self.validate._branch, self.schema.literal(ns.bsfs.Literal),
+ ast.fetch.Fetch(ns.bse.tag, ast.fetch.This('this')))
+ self.assertRaises(errors.ConsistencyError, self.validate._branch, self.schema.literal(ns.bsfs.Literal),
+ ast.fetch.Value(ns.bse.filename, 'value'))
+ self.assertRaises(errors.ConsistencyError, self.validate._branch, self.schema.literal(ns.bsfs.Literal),
+ ast.fetch.Node(ns.bse.tag, 'node'))
+ # type must be in the schema
+ self.assertRaises(errors.ConsistencyError, self.validate._branch, self.schema.node(ns.bsfs.Node).child(ns.bsfs.Invalid),
+ ast.fetch._Branch(ns.bse.filename))
+ self.assertRaises(errors.ConsistencyError, self.validate._branch, self.schema.node(ns.bsfs.Node).child(ns.bsfs.Invalid),
+ ast.fetch.Fetch(ns.bse.tag, ast.fetch.This('this')))
+ self.assertRaises(errors.ConsistencyError, self.validate._branch, self.schema.node(ns.bsfs.Node).child(ns.bsfs.Invalid),
+ ast.fetch.Value(ns.bse.filename, 'value'))
+ self.assertRaises(errors.ConsistencyError, self.validate._branch, self.schema.node(ns.bsfs.Node).child(ns.bsfs.Invalid),
+ ast.fetch.Node(ns.bse.tag, 'node'))
+ # predicate must be in the schema
+ self.assertRaises(errors.ConsistencyError, self.validate._branch, self.schema.node(ns.bsfs.Entity),
+ ast.fetch._Branch(ns.bse.invalid))
+ self.assertRaises(errors.ConsistencyError, self.validate._branch, self.schema.node(ns.bsfs.Entity),
+ ast.fetch.Fetch(ns.bse.invalid, ast.fetch.This('this')))
+ self.assertRaises(errors.ConsistencyError, self.validate._branch, self.schema.node(ns.bsfs.Entity),
+ ast.fetch.Value(ns.bse.invalid, 'value'))
+ self.assertRaises(errors.ConsistencyError, self.validate._branch, self.schema.node(ns.bsfs.Entity),
+ ast.fetch.Node(ns.bse.invalid, 'node'))
+ # predicate's domain must be related to the type
+ self.assertRaises(errors.ConsistencyError, self.validate._branch, self.schema.node(ns.bsfs.Entity),
+ ast.fetch._Branch(ns.bse.label))
+ self.assertRaises(errors.ConsistencyError, self.validate._branch, self.schema.node(ns.bsfs.Entity),
+ ast.fetch.Fetch(ns.bse.label, ast.fetch.This('this')))
+ self.assertRaises(errors.ConsistencyError, self.validate._branch, self.schema.node(ns.bsfs.Entity),
+ ast.fetch.Node(ns.bse.label, 'node'))
+ self.assertRaises(errors.ConsistencyError, self.validate._branch, self.schema.node(ns.bsfs.Entity),
+ ast.fetch.Value(ns.bse.label, 'value'))
+ # predicate's domain cannot be a supertype
+ self.assertRaises(errors.ConsistencyError, self.validate._branch, self.schema.node(ns.bsfs.Node),
+ ast.fetch._Branch(ns.bse.tag))
+ self.assertRaises(errors.ConsistencyError, self.validate._branch, self.schema.node(ns.bsfs.Node),
+ ast.fetch.Fetch(ns.bse.tag, ast.fetch.This('this')))
+ self.assertRaises(errors.ConsistencyError, self.validate._branch, self.schema.node(ns.bsfs.Node),
+ ast.fetch.Node(ns.bse.tag, 'node'))
+ self.assertRaises(errors.ConsistencyError, self.validate._branch, self.schema.node(ns.bsfs.Node),
+ ast.fetch.Value(ns.bse.tag, 'value'))
+ # predicate's domain can be a subtype
+ self.assertIsNone(self.validate._branch(self.schema.node(ns.bsfs.Entity),
+ ast.fetch._Branch(ns.bse.filename)))
+ self.assertIsNone(self.validate._branch(self.schema.node(ns.bsfs.Entity),
+ ast.fetch.Value(ns.bse.filename, 'value')))
+
+ def test_fetch(self):
+ # fetch accepts correct expressions
+ self.assertIsNone(self.validate._fetch(self.schema.node(ns.bsfs.Node),
+ ast.fetch.Fetch(ns.bse.tag, ast.fetch.Value(ns.bse.label, 'value'))))
+ # range must be a node
+ self.assertRaises(errors.ConsistencyError, self.validate._fetch, self.schema.node(ns.bsfs.Node),
+ ast.fetch.Fetch(ns.bse.filename, ast.fetch.This('this')))
+ # child expression must be valid
+ self.assertRaises(errors.ConsistencyError, self.validate._fetch, self.schema.node(ns.bsfs.Node),
+ ast.fetch.Fetch(ns.bse.tag, ast.fetch.Node(ns.bse.label, 'node')))
+
+ def test_named(self):
+ # named accepts correct expressions
+ self.assertIsNone(self.validate._named(self.schema.node(ns.bsfs.Entity),
+ ast.fetch.Node(ns.bse.tag, 'node')))
+ self.assertIsNone(self.validate._named(self.schema.node(ns.bsfs.Entity),
+ ast.fetch.Value(ns.bse.filename, 'value')))
+ # name must be non-empty
+ self.assertRaises(errors.BackendError, self.validate._named, self.schema.node(ns.bsfs.Entity),
+ ast.fetch.Node(ns.bse.tag, ''))
+ self.assertRaises(errors.BackendError, self.validate._named, self.schema.node(ns.bsfs.Entity),
+ ast.fetch.Value(ns.bse.filename, ''))
+
+ def test_node(self):
+ # node accepts correct expressions
+ self.assertIsNone(self.validate._node(self.schema.node(ns.bsfs.Entity),
+ ast.fetch.Node(ns.bse.tag, 'node')))
+ # range must be a node
+ self.assertRaises(errors.ConsistencyError, self.validate._node, self.schema.node(ns.bsfs.Entity),
+ ast.fetch.Node(ns.bse.filename, 'node'))
+
+ def test_value(self):
+ # value accepts correct expressions
+ self.assertIsNone(self.validate._value(self.schema.node(ns.bsfs.Entity),
+ ast.fetch.Value(ns.bse.filename, 'value')))
+ # range must be a literal
+ self.assertRaises(errors.ConsistencyError, self.validate._value, self.schema.node(ns.bsfs.Entity),
+ ast.fetch.Value(ns.bse.tag, 'value'))
+
+ def test_this(self):
+ # this accepts correct expressions
+ self.assertIsNone(self.validate._this(self.schema.node(ns.bsfs.Entity), ast.fetch.This('this')))
+ # type must be a node
+ self.assertRaises(errors.ConsistencyError, self.validate._this, self.schema.literal(ns.bsfs.Literal),
+ ast.fetch.This('this'))
+ self.assertRaises(errors.ConsistencyError, self.validate._this, self.schema.predicate(ns.bsfs.Predicate),
+ ast.fetch.This('this'))
+ # type must be in the schema
+ self.assertRaises(errors.ConsistencyError, self.validate._this, self.schema.node(ns.bsfs.Node).child(ns.bsfs.Invalid),
+ ast.fetch.This('this'))
+ # name must be non-empty
+ self.assertRaises(errors.BackendError, self.validate._this, self.schema.node(ns.bsfs.Entity), ast.fetch.This(''))
+
+
+## main ##
+
+if __name__ == '__main__':
+ unittest.main()
+
+## EOF ##