aboutsummaryrefslogtreecommitdiffstats
path: root/test/graph/test_resolve.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/graph/test_resolve.py
parent91437ba89d35bf482f3d9671bb99ef2fc69f5985 (diff)
parente4845c627e97a6d125bf33d9e7a4a8d373d7fc4a (diff)
downloadbsfs-0.23.03.tar.gz
bsfs-0.23.03.tar.bz2
bsfs-0.23.03.zip
Merge branch 'develop'v0.23.03
Diffstat (limited to 'test/graph/test_resolve.py')
-rw-r--r--test/graph/test_resolve.py199
1 files changed, 199 insertions, 0 deletions
diff --git a/test/graph/test_resolve.py b/test/graph/test_resolve.py
new file mode 100644
index 0000000..e09b1cc
--- /dev/null
+++ b/test/graph/test_resolve.py
@@ -0,0 +1,199 @@
+
+# imports
+import unittest
+
+# bsie imports
+from bsfs import schema as bsc
+from bsfs.graph import Graph, nodes
+from bsfs.namespace import ns
+from bsfs.query import ast
+from bsfs.triple_store import SparqlStore
+from bsfs.utils import URI, errors
+
+# objects to test
+from bsfs.graph.resolve import Filter
+
+
+## code ##
+
+ns.bse = ns.bsfs.Entity()
+
+class TestFilter(unittest.TestCase):
+ """
+
+ NOTE: The Filter resolver is relatively simple as it only checks and changes
+ ast.filter.Is instances. Hence, we don't test all methods individually but
+ all of them with respect to ast.filter.Is elements.
+
+ """
+
+ def test_call(self): # tests resolve implicitly
+ schema = bsc.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/>
+ prefix bsa: <https://schema.bsfs.io/core/Literal/Array/>
+
+ bsfs:Entity rdfs:subClassOf bsfs:Node .
+ bsfs:Tag rdfs:subClassOf bsfs:Node .
+ xsd:string rdfs:subClassOf bsfs:Literal .
+ bsl:Number rdfs:subClassOf bsfs:Literal .
+ bsl:Array rdfs:subClassOf bsfs:Literal .
+ bsa:Feature rdfs:subClassOf bsl:Array .
+ xsd:integer rdfs:subClassOf bsl:Number .
+
+ bsfs:Colors rdfs:subClassOf bsa:Feature ;
+ bsfs:dimension "5"^^xsd:integer .
+
+ bse:colors rdfs:subClassOf bsfs:Predicate ;
+ rdfs:domain bsfs:Entity ;
+ rdfs:range bsfs:Colors .
+
+ bse:comment rdfs:subClassOf bsfs:Predicate ;
+ rdfs:domain bsfs:Entity ;
+ 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 "false"^^xsd:boolean .
+
+ bse:tag rdfs:subClassOf bsfs:Predicate ;
+ rdfs:domain bsfs:Entity ;
+ rdfs:range bsfs:Tag ;
+ bsfs:unique "false"^^xsd:boolean .
+ ''')
+ backend = SparqlStore.Open()
+ backend.schema = schema
+ graph = Graph(backend, URI('http://example.com/me'))
+ ents = graph.nodes(ns.bsfs.Entity,
+ {URI('http://example.com/me/entity#1234'), URI('http://example.com/me/entity#4321')})
+ tags = graph.nodes(ns.bsfs.Tag,
+ {URI('http://example.com/me/tag#1234'), URI('http://example.com/me/tag#4321')})
+ invalid = nodes.Nodes(None, '', schema.node(ns.bsfs.Node).child(ns.bsfs.Invalid),
+ {'http://example.com/you/invalid#1234', 'http://example.com/you/invalid#4321'})
+ resolver = Filter(schema)
+
+ # query can be None
+ self.assertIsNone(resolver(schema.node(ns.bsfs.Entity), None))
+
+ # immediate Is
+ self.assertEqual(resolver(schema.node(ns.bsfs.Entity),
+ ast.filter.Is(ents)),
+ ast.filter.Or(
+ ast.filter.Is('http://example.com/me/entity#1234'),
+ ast.filter.Is('http://example.com/me/entity#4321')
+ ))
+ # only resolves nodes instances, not URIs
+ self.assertEqual(resolver(schema.node(ns.bsfs.Entity),
+ ast.filter.Is('http://example.com/me/entity#1234')),
+ ast.filter.Is('http://example.com/me/entity#1234'))
+ self.assertEqual(resolver(schema.node(ns.bsfs.Entity),
+ ast.filter.Is(1234)),
+ ast.filter.Is(1234))
+
+ # within And (also checks _value)
+ self.assertEqual(resolver(schema.node(ns.bsfs.Entity),
+ ast.filter.And(
+ ast.filter.Is(ents),
+ ast.filter.Any(ns.bse.comment, ast.filter.Equals('hello world')),
+ )),
+ ast.filter.And(
+ ast.filter.Or(
+ ast.filter.Is('http://example.com/me/entity#1234'),
+ ast.filter.Is('http://example.com/me/entity#4321')),
+ ast.filter.Any(ns.bse.comment, ast.filter.Equals('hello world'))
+ ))
+ # within Or (checks _bounded)
+ self.assertEqual(resolver(schema.node(ns.bsfs.Entity),
+ ast.filter.Or(
+ ast.filter.Is(ents),
+ ast.filter.Any(ns.bse.filesize, ast.filter.LessThan(5)),
+ )),
+ ast.filter.Or(
+ ast.filter.Or(
+ ast.filter.Is('http://example.com/me/entity#1234'),
+ ast.filter.Is('http://example.com/me/entity#4321')),
+ ast.filter.Any(ns.bse.filesize, ast.filter.LessThan(5))
+ ))
+
+ # Any-branched Is
+ self.assertEqual(resolver(schema.node(ns.bsfs.Entity),
+ ast.filter.Any(ns.bse.tag, ast.filter.Is(tags))),
+ ast.filter.Any(ns.bse.tag, ast.filter.Or(
+ ast.filter.Is('http://example.com/me/tag#1234'),
+ ast.filter.Is('http://example.com/me/tag#4321')),
+ ))
+ # All-branched Is
+ self.assertEqual(resolver(schema.node(ns.bsfs.Entity),
+ ast.filter.All(ns.bse.tag, ast.filter.Is(tags))),
+ ast.filter.All(ns.bse.tag, ast.filter.Or(
+ ast.filter.Is('http://example.com/me/tag#1234'),
+ ast.filter.Is('http://example.com/me/tag#4321')),
+ ))
+ # Negated predicate
+ self.assertEqual(resolver(schema.node(ns.bsfs.Tag),
+ ast.filter.Any(ast.filter.Predicate(ns.bse.tag, reverse=True), ast.filter.Is(ents))),
+ ast.filter.Any(ast.filter.Predicate(ns.bse.tag, reverse=True), ast.filter.Or(
+ ast.filter.Is('http://example.com/me/entity#1234'),
+ ast.filter.Is('http://example.com/me/entity#4321')),
+ ))
+
+ # negated Is
+ self.assertEqual(resolver(schema.node(ns.bsfs.Entity),
+ ast.filter.Not(ast.filter.Is(ents))),
+ ast.filter.Not(
+ ast.filter.Or(
+ ast.filter.Is('http://example.com/me/entity#1234'),
+ ast.filter.Is('http://example.com/me/entity#4321')),
+ ))
+
+ # for sake of completeness: Has
+ self.assertEqual(resolver(schema.node(ns.bsfs.Entity),
+ ast.filter.Has(ns.bse.comment)),
+ ast.filter.Has(ns.bse.comment))
+ # for sake of completeness: Distance
+ self.assertEqual(resolver(schema.node(ns.bsfs.Entity),
+ ast.filter.Any(ns.bse.colors, ast.filter.Distance([1,2,3,4,5], 1))),
+ ast.filter.Any(ns.bse.colors, ast.filter.Distance([1,2,3,4,5], 1)))
+ # route errors
+ self.assertRaises(errors.BackendError, resolver, schema.node(ns.bsfs.Tag),
+ ast.filter.Predicate(ns.bse.comment))
+ self.assertRaises(errors.BackendError, resolver, schema.node(ns.bsfs.Tag),
+ ast.filter.Any(ast.filter.PredicateExpression(), ast.filter.Equals('foo')))
+ self.assertRaises(errors.BackendError, resolver._one_of, ast.filter.OneOf(ast.filter.Predicate(ns.bsfs.Predicate)))
+ # for sake of coverage completeness: valid OneOf
+ self.assertIsNotNone(resolver._one_of(ast.filter.OneOf(ast.filter.Predicate(ns.bse.colors))))
+
+ # check schema consistency
+ self.assertRaises(errors.ConsistencyError, resolver, schema.node(ns.bsfs.Tag),
+ ast.filter.Is(invalid))
+ # check immediate type compatibility
+ self.assertRaises(errors.ConsistencyError, resolver, schema.node(ns.bsfs.Tag),
+ ast.filter.Is(ents))
+ self.assertRaises(errors.ConsistencyError, resolver, schema.node(ns.bsfs.Entity),
+ ast.filter.Is(tags))
+ # check type compatibility through branches
+ self.assertRaises(errors.ConsistencyError, resolver, schema.node(ns.bsfs.Tag),
+ ast.filter.Any(ns.bse.comment, ast.filter.Is(tags)))
+ self.assertRaises(errors.ConsistencyError, resolver, schema.node(ns.bsfs.Tag),
+ ast.filter.Any(ns.bse.invalid, ast.filter.Is(tags)))
+ self.assertRaises(errors.ConsistencyError, resolver, schema.node(ns.bsfs.Tag),
+ ast.filter.Any(ast.filter.OneOf(ns.bse.comment, ns.bse.tag), ast.filter.Is(tags)))
+ self.assertRaises(errors.ConsistencyError, resolver, schema.node(ns.bsfs.Tag),
+ ast.filter.Any(ast.filter.OneOf(ns.bse.comment, ns.bse.filesize), ast.filter.Is(tags)))
+ self.assertRaises(errors.ConsistencyError, resolver, schema.node(ns.bsfs.Tag),
+ ast.filter.Any(ast.filter.Predicate(ns.bse.tag, reverse=True), ast.filter.Is(tags)))
+
+
+
+## main ##
+
+if __name__ == '__main__':
+ unittest.main()
+
+## EOF ##