aboutsummaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/graph/ac/test_null.py10
-rw-r--r--test/graph/test_graph.py55
-rw-r--r--test/graph/test_nodes.py30
-rw-r--r--test/graph/test_resolve.py181
4 files changed, 266 insertions, 10 deletions
diff --git a/test/graph/ac/test_null.py b/test/graph/ac/test_null.py
index f39c9be..c863943 100644
--- a/test/graph/ac/test_null.py
+++ b/test/graph/ac/test_null.py
@@ -10,6 +10,7 @@ import unittest
# bsie imports
from bsfs import schema as _schema
from bsfs.namespace import ns
+from bsfs.query import ast
from bsfs.triple_store import SparqlStore
from bsfs.utils import URI
@@ -93,6 +94,15 @@ class TestNullAC(unittest.TestCase):
ac = NullAC(self.backend, self.user)
self.assertSetEqual(self.ent_ids, ac.createable(self.ent_type, self.ent_ids))
+ def test_filter_read(self):
+ query = ast.filter.Or(
+ ast.filter.Any(ns.bse.tag, ast.filter.Is('http://example.com/tag#1234')),
+ ast.filter.Any(ns.bse.tag, ast.filter.Is('http://example.com/tag#4321')),
+ ast.filter.Any(ns.bse.author, ast.filter.Equals('Me, Myself, and I')))
+ ac = NullAC(self.backend, self.user)
+ self.assertEqual(query, ac.filter_read(self.ent_type, query))
+ return query
+
## main ##
diff --git a/test/graph/test_graph.py b/test/graph/test_graph.py
index 0a3fd5b..8503d5b 100644
--- a/test/graph/test_graph.py
+++ b/test/graph/test_graph.py
@@ -9,10 +9,11 @@ import unittest
# bsie imports
from bsfs import schema
+from bsfs.graph.nodes import Nodes
from bsfs.namespace import ns
+from bsfs.query import ast
from bsfs.triple_store import SparqlStore
from bsfs.utils import URI, errors
-from bsfs.graph.nodes import Nodes
# objects to test
from bsfs.graph.graph import Graph
@@ -193,7 +194,57 @@ class TestGraph(unittest.TestCase):
'''))
def test_get(self):
- raise NotImplementedError()
+ # setup
+ graph = Graph(self.backend, self.user)
+ graph.migrate(schema.Schema.from_string('''
+ prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
+ prefix xsd: <http://www.w3.org/2001/XMLSchema#>
+ prefix bsfs: <http://bsfs.ai/schema/>
+ prefix bse: <http://bsfs.ai/schema/Entity#>
+
+ bsfs:Entity rdfs:subClassOf bsfs:Node .
+ bsfs:Tag rdfs:subClassOf bsfs:Node .
+ xsd:string rdfs:subClassOf bsfs:Literal .
+
+ bse:tag rdfs:subClassOf bsfs:Predicate ;
+ rdfs:domain bsfs:Entity ;
+ rdfs:range bsfs:Tag ;
+ bsfs:unique "false"^^xsd:boolean .
+
+ bse:comment rdfs:subClassOf bsfs:Predicate ;
+ rdfs:domain bsfs:Node ;
+ rdfs:range xsd:string ;
+ bsfs:unique "false"^^xsd:boolean .
+
+ '''))
+ # add some instances
+ ents = graph.nodes(ns.bsfs.Entity, {URI('http://example.com/entity#1234'), URI('http://example.com/entity#4321')})
+ tags = graph.nodes(ns.bsfs.Tag, {URI('http://example.com/tag#1234'), URI('http://example.com/tag#4321')})
+ # add some node links
+ ents.set(ns.bse.tag, tags)
+ # add some literals
+ graph.node(ns.bsfs.Entity, URI('http://example.com/entity#1234')).set(ns.bse.comment, 'hello world')
+ graph.node(ns.bsfs.Entity, URI('http://example.com/entity#1234')).set(ns.bse.comment, 'foo')
+ graph.node(ns.bsfs.Entity, URI('http://example.com/entity#1234')).set(ns.bse.comment, 'foobar')
+ graph.node(ns.bsfs.Tag, URI('http://example.com/tag#1234')).set(ns.bse.comment, 'foo')
+ graph.node(ns.bsfs.Tag, URI('http://example.com/tag#4321')).set(ns.bse.comment, 'bar')
+
+ # get exception for invalid query
+ self.assertRaises(errors.ConsistencyError, graph.get, ns.bsfs.Entity, ast.filter.Any(ns.bse.tag, ast.filter.Equals('hello world')))
+
+ # query returns nodes
+ self.assertEqual(graph.get(ns.bsfs.Entity, ast.filter.Any(ns.bse.tag, ast.filter.Is(tags))), ents)
+ self.assertEqual(graph.get(ns.bsfs.Entity, ast.filter.Any(ns.bse.comment, ast.filter.StartsWith('foo'))),
+ graph.node(ns.bsfs.Entity, URI('http://example.com/entity#1234')))
+ self.assertEqual(graph.get(ns.bsfs.Node, ast.filter.Any(ns.bse.comment, ast.filter.StartsWith('foo'))),
+ graph.nodes(ns.bsfs.Node, {URI('http://example.com/entity#1234'), URI('http://example.com/tag#1234')}))
+ self.assertEqual(graph.get(ns.bsfs.Entity, ast.filter.Or(
+ ast.filter.Any(ns.bse.comment, ast.filter.EndsWith('bar')),
+ ast.filter.Any(ns.bse.tag, ast.filter.All(ns.bse.comment, ast.filter.Equals('bar'))))),
+ ents)
+
+
+
## main ##
diff --git a/test/graph/test_nodes.py b/test/graph/test_nodes.py
index 43e7f6f..11ae46d 100644
--- a/test/graph/test_nodes.py
+++ b/test/graph/test_nodes.py
@@ -72,6 +72,20 @@ class TestNodes(unittest.TestCase):
bsfs:unique "true"^^xsd:boolean .
''')
+ self.schema_triples = {
+ # schema hierarchy
+ (rdflib.URIRef(ns.bsfs.Entity), rdflib.RDFS.subClassOf, rdflib.URIRef(ns.bsfs.Node)),
+ (rdflib.URIRef(ns.bsfs.Tag), rdflib.RDFS.subClassOf, rdflib.URIRef(ns.bsfs.Node)),
+ (rdflib.URIRef(ns.bsfs.User), rdflib.RDFS.subClassOf, rdflib.URIRef(ns.bsfs.Node)),
+ (rdflib.URIRef(ns.xsd.string), rdflib.RDFS.subClassOf, rdflib.URIRef(ns.bsfs.Literal)),
+ (rdflib.URIRef(ns.xsd.integer), rdflib.RDFS.subClassOf, rdflib.URIRef(ns.bsfs.Literal)),
+ (rdflib.URIRef(ns.bsm.t_created), rdflib.RDFS.subClassOf, rdflib.URIRef(ns.bsfs.Predicate)),
+ (rdflib.URIRef(ns.bse.comment), rdflib.RDFS.subClassOf, rdflib.URIRef(ns.bsfs.Predicate)),
+ (rdflib.URIRef(ns.bse.filesize), rdflib.RDFS.subClassOf, rdflib.URIRef(ns.bsfs.Predicate)),
+ (rdflib.URIRef(ns.bse.tag), rdflib.RDFS.subClassOf, rdflib.URIRef(ns.bsfs.Predicate)),
+ (rdflib.URIRef(ns.bse.author), rdflib.RDFS.subClassOf, rdflib.URIRef(ns.bsfs.Predicate)),
+ (rdflib.URIRef('http://bsfs.ai/schema/Tag#representative'), rdflib.RDFS.subClassOf, rdflib.URIRef(ns.bsfs.Predicate)),
+ }
# Nodes constructor args
self.user = URI('http://example.com/me')
# set args
@@ -160,7 +174,7 @@ class TestNodes(unittest.TestCase):
time_triples = list(self.backend._graph.objects(rdflib.URIRef('http://example.com/me/entity#1234'), rdflib.URIRef(self.t_created.uri)))
t_ent_created = float(time_triples[0]) if len(time_triples) > 0 else 0.0
# check triples
- self.assertSetEqual(set(self.backend._graph), {
+ self.assertSetEqual(set(self.backend._graph), self.schema_triples | {
# entity definitions
(rdflib.URIRef('http://example.com/me/entity#1234'), rdflib.RDF.type, rdflib.URIRef('http://bsfs.ai/schema/Entity')),
(rdflib.URIRef('http://example.com/me/entity#4321'), rdflib.RDF.type, rdflib.URIRef('http://bsfs.ai/schema/Entity')),
@@ -171,7 +185,7 @@ class TestNodes(unittest.TestCase):
# existing nodes remain unchanged
self.assertSetEqual(self.ent_ids, nodes._ensure_nodes(self.ent_type, self.ent_ids))
- self.assertSetEqual(set(self.backend._graph), {
+ self.assertSetEqual(set(self.backend._graph), self.schema_triples | {
# entity definitions
(rdflib.URIRef('http://example.com/me/entity#1234'), rdflib.RDF.type, rdflib.URIRef('http://bsfs.ai/schema/Entity')),
(rdflib.URIRef('http://example.com/me/entity#4321'), rdflib.RDF.type, rdflib.URIRef('http://bsfs.ai/schema/Entity')),
@@ -186,7 +200,7 @@ class TestNodes(unittest.TestCase):
time_triples = list(self.backend._graph.objects(rdflib.URIRef('http://example.com/me/tag#1234'), rdflib.URIRef(self.t_created.uri)))
t_tag_created = float(time_triples[0]) if len(time_triples) > 0 else 0.0
# check triples
- self.assertSetEqual(set(self.backend._graph), {
+ self.assertSetEqual(set(self.backend._graph), self.schema_triples | {
# previous triples
(rdflib.URIRef('http://example.com/me/entity#1234'), rdflib.RDF.type, rdflib.URIRef('http://bsfs.ai/schema/Entity')),
(rdflib.URIRef('http://example.com/me/entity#4321'), rdflib.RDF.type, rdflib.URIRef('http://bsfs.ai/schema/Entity')),
@@ -202,7 +216,7 @@ class TestNodes(unittest.TestCase):
def test___set(self):
# setup
nodes = Nodes(self.backend, self.user, self.ent_type, {URI('http://example.com/me/entity#1234'), URI('http://example.com/me/entity#4321')})
- self.assertSetEqual(set(self.backend._graph), set())
+ self.assertSetEqual(set(self.backend._graph), self.schema_triples | set())
set_ = nodes._Nodes__set
# node_type must match predicate's domain
@@ -217,7 +231,7 @@ class TestNodes(unittest.TestCase):
time_triples = list(self.backend._graph.objects(rdflib.URIRef('http://example.com/me/entity#1234'), rdflib.URIRef(self.t_created.uri)))
t_ent_created = float(time_triples[0]) if len(time_triples) > 0 else 0.0
# verify triples
- self.assertSetEqual(set(self.backend._graph), {
+ self.assertSetEqual(set(self.backend._graph), self.schema_triples | {
# entity definitions
(rdflib.URIRef('http://example.com/me/entity#1234'), rdflib.RDF.type, rdflib.URIRef('http://bsfs.ai/schema/Entity')),
(rdflib.URIRef('http://example.com/me/entity#4321'), rdflib.RDF.type, rdflib.URIRef('http://bsfs.ai/schema/Entity')),
@@ -236,7 +250,7 @@ class TestNodes(unittest.TestCase):
time_triples = list(self.backend._graph.objects(rdflib.URIRef('http://example.com/me/tag#1234'), rdflib.URIRef(self.t_created.uri)))
t_tag_created = float(time_triples[0]) if len(time_triples) > 0 else 0.0
# verify triples
- self.assertSetEqual(set(self.backend._graph), {
+ self.assertSetEqual(set(self.backend._graph), self.schema_triples | {
# previous values
(rdflib.URIRef('http://example.com/me/entity#1234'), rdflib.RDF.type, rdflib.URIRef('http://bsfs.ai/schema/Entity')),
(rdflib.URIRef('http://example.com/me/entity#4321'), rdflib.RDF.type, rdflib.URIRef('http://bsfs.ai/schema/Entity')),
@@ -265,7 +279,7 @@ class TestNodes(unittest.TestCase):
Nodes(self.backend, self.user, self.ent_type, self.ent_ids))
def test_set(self):
- self.assertSetEqual(set(self.backend._graph), set())
+ self.assertSetEqual(set(self.backend._graph), self.schema_triples | set())
nodes = Nodes(self.backend, self.user, self.ent_type, self.ent_ids)
# can set literal values
self.assertEqual(nodes, nodes.set(self.p_filesize.uri, 1234))
@@ -312,7 +326,7 @@ class TestNodes(unittest.TestCase):
def test_set_from_iterable(self):
- self.assertSetEqual(set(self.backend._graph), set())
+ self.assertSetEqual(set(self.backend._graph), self.schema_triples | set())
nodes = Nodes(self.backend, self.user, self.ent_type, self.ent_ids)
# can set literal and node values simultaneously
self.assertEqual(nodes, nodes.set_from_iterable({
diff --git a/test/graph/test_resolve.py b/test/graph/test_resolve.py
new file mode 100644
index 0000000..5bc99e4
--- /dev/null
+++ b/test/graph/test_resolve.py
@@ -0,0 +1,181 @@
+"""
+
+Part of the bsfs test suite.
+A copy of the license is provided with the project.
+Author: Matthias Baumgartner, 2022
+"""
+# 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 ##
+
+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):
+ schema = bsc.Schema.from_string('''
+ prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
+ prefix xsd: <http://www.w3.org/2001/XMLSchema#>
+
+ prefix bsfs: <http://bsfs.ai/schema/>
+ prefix bse: <http://bsfs.ai/schema/Entity#>
+
+ bsfs:Entity rdfs:subClassOf bsfs:Node .
+ bsfs:Tag rdfs:subClassOf bsfs:Node .
+ xsd:string rdfs:subClassOf bsfs:Literal .
+ xsd:integer rdfs:subClassOf bsfs:Literal .
+
+ 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).get_child(ns.bsfs.Invalid),
+ {'http://example.com/you/invalid#1234', 'http://example.com/you/invalid#4321'})
+ resolver = Filter(schema)
+
+ # 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))
+ # 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.UnreachableError, resolver._one_of, ast.filter.OneOf(ast.filter.Predicate(ns.bsfs.Predicate)))
+
+ # 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 ##