aboutsummaryrefslogtreecommitdiffstats
path: root/test/graph/test_graph.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_graph.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/graph/test_graph.py')
-rw-r--r--test/graph/test_graph.py258
1 files changed, 202 insertions, 56 deletions
diff --git a/test/graph/test_graph.py b/test/graph/test_graph.py
index 33cf6aa..167168d 100644
--- a/test/graph/test_graph.py
+++ b/test/graph/test_graph.py
@@ -1,18 +1,17 @@
-"""
-Part of the bsfs test suite.
-A copy of the license is provided with the project.
-Author: Matthias Baumgartner, 2022
-"""
# imports
+from functools import reduce
+import operator
import unittest
# bsie imports
from bsfs import schema
+from bsfs.graph.ac import NullAC
+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
@@ -20,83 +19,95 @@ from bsfs.graph.graph import Graph
## code ##
+ns.bse = ns.bsfs.Entity()
+
class TestGraph(unittest.TestCase):
def setUp(self):
- self.user = URI('http://example.com/me')
self.backend = SparqlStore.Open()
- self.backend.schema = schema.Schema.from_string('''
+ self.backend.schema = schema.from_string('''
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
- prefix bsfs: <http://bsfs.ai/schema/>
+ prefix bsfs: <https://schema.bsfs.io/core/>
bsfs:Entity rdfs:subClassOf bsfs:Node .
''')
+ self.user = URI('http://example.com/me')
+ self.ac = NullAC(self.backend, self.user)
def test_str(self):
- self.assertEqual(str(Graph(self.backend, self.user)),
- 'Graph(SparqlStore(uri=None), http://example.com/me)')
- self.assertEqual(repr(Graph(self.backend, self.user)),
- 'Graph(backend=SparqlStore(uri=None), user=http://example.com/me)')
+ self.assertEqual(str(Graph(self.backend, self.ac)),
+ 'Graph(SparqlStore(uri=None))')
+ self.assertEqual(repr(Graph(self.backend, self.ac)),
+ 'Graph(SparqlStore(uri=None), NullAC(http://example.com/me))')
# str respects backend
class Foo(SparqlStore): pass
- self.assertEqual(str(Graph(Foo.Open(), self.user)),
- 'Graph(Foo(uri=None), http://example.com/me)')
- self.assertEqual(repr(Graph(Foo.Open(), self.user)),
- 'Graph(backend=Foo(uri=None), user=http://example.com/me)')
+ self.assertEqual(str(Graph(Foo.Open(), self.ac)),
+ 'Graph(Foo(uri=None))')
+ self.assertEqual(repr(Graph(Foo.Open(), self.ac)),
+ 'Graph(Foo(uri=None), NullAC(http://example.com/me))')
# str respect user
- self.assertEqual(str(Graph(self.backend, URI('http://example.com/you'))),
- 'Graph(SparqlStore(uri=None), http://example.com/you)')
- self.assertEqual(repr(Graph(self.backend, URI('http://example.com/you'))),
- 'Graph(backend=SparqlStore(uri=None), user=http://example.com/you)')
+ self.assertEqual(str(Graph(self.backend, NullAC(self.backend, URI('http://example.com/you')))),
+ 'Graph(SparqlStore(uri=None))')
+ self.assertEqual(repr(Graph(self.backend, NullAC(self.backend, URI('http://example.com/you')))),
+ 'Graph(SparqlStore(uri=None), NullAC(http://example.com/you))')
# str respects type
class Bar(Graph): pass
- self.assertEqual(str(Bar(self.backend, self.user)),
- 'Bar(SparqlStore(uri=None), http://example.com/me)')
- self.assertEqual(repr(Bar(self.backend, self.user)),
- 'Bar(backend=SparqlStore(uri=None), user=http://example.com/me)')
+ self.assertEqual(str(Bar(self.backend, self.ac)),
+ 'Bar(SparqlStore(uri=None))')
+ self.assertEqual(repr(Bar(self.backend, self.ac)),
+ 'Bar(SparqlStore(uri=None), NullAC(http://example.com/me))')
def test_equality(self):
- graph = Graph(self.backend, self.user)
+ graph = Graph(self.backend, self.ac)
# instance is equal to itself
self.assertEqual(graph, graph)
self.assertEqual(hash(graph), hash(graph))
# instance is equal to a clone
- self.assertEqual(graph, Graph(self.backend, self.user))
- self.assertEqual(hash(graph), hash(Graph(self.backend, self.user)))
+ self.assertEqual(graph, Graph(self.backend, self.ac))
+ self.assertEqual(hash(graph), hash(Graph(self.backend, self.ac)))
# equality respects backend
- self.assertNotEqual(graph, Graph(SparqlStore.Open(), self.user))
- self.assertNotEqual(hash(graph), hash(Graph(SparqlStore.Open(), self.user)))
+ self.assertNotEqual(graph, Graph(SparqlStore.Open(), self.ac))
+ self.assertNotEqual(hash(graph), hash(Graph(SparqlStore.Open(), self.ac)))
# equality respects user
self.assertNotEqual(graph, Graph(self.backend, URI('http://example.com/you')))
self.assertNotEqual(hash(graph), hash(Graph(self.backend, URI('http://example.com/you'))))
def test_essentials(self):
- graph = Graph(self.backend, self.user)
+ graph = Graph(self.backend, self.ac)
# schema
self.assertEqual(graph.schema, self.backend.schema)
self.assertRaises(AttributeError, setattr, graph, 'schema', None)
def test_node(self):
- graph = Graph(self.backend, self.user)
+ graph = Graph(self.backend, self.ac)
guid = URI('http://example.com/me/entity#1234')
# returns a Nodes instance
self.assertEqual(
graph.node(ns.bsfs.Entity, guid),
- Nodes(self.backend, self.user, graph.schema.node(ns.bsfs.Entity), {guid}))
+ Nodes(self.backend, self.ac, graph.schema.node(ns.bsfs.Entity), {guid}))
# node_type must be in the schema
self.assertRaises(KeyError, graph.node, ns.bsfs.Invalid, guid)
def test_nodes(self):
- graph = Graph(self.backend, self.user)
+ graph = Graph(self.backend, self.ac)
guids = {URI('http://example.com/me/entity#1234'), URI('http://example.com/me/entity#4321')}
# returns a Nodes instance
self.assertEqual(
graph.nodes(ns.bsfs.Entity, guids),
- Nodes(self.backend, self.user, graph.schema.node(ns.bsfs.Entity), guids))
+ Nodes(self.backend, self.ac, graph.schema.node(ns.bsfs.Entity), guids))
# node_type must be in the schema
self.assertRaises(KeyError, graph.nodes, ns.bsfs.Invalid, guids)
+ def test_empty(self):
+ graph = Graph(self.backend, self.ac)
+ # returns a Nodes instance
+ self.assertEqual(
+ graph.empty(ns.bsfs.Entity),
+ Nodes(self.backend, self.ac, graph.schema.node(ns.bsfs.Entity), set()))
+ # node_type must be in the schema
+ self.assertRaises(KeyError, graph.empty, ns.bsfs.Invalid)
+
def test_migrate(self):
# setup
- graph = Graph(self.backend, self.user)
+ graph = Graph(self.backend, self.ac)
# argument must be a schema
class Foo(): pass
@@ -117,14 +128,16 @@ class TestGraph(unittest.TestCase):
schema.Node(ns.bsfs.Node, None)))}), append=False)
# can migrate to compatible schema
- target_1 = schema.Schema.from_string('''
+ target_1 = 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#>
+ 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 .
xsd:string rdfs:subClassOf bsfs:Literal .
- xsd:integer rdfs:subClassOf bsfs:Literal .
+ bsl:Number rdfs:subClassOf bsfs:Literal .
+ xsd:integer rdfs:subClassOf bsl:Number .
bse:filename rdfs:subClassOf bsfs:Predicate ;
rdfs:domain bsfs:Entity ;
@@ -141,27 +154,31 @@ class TestGraph(unittest.TestCase):
# new schema is applied
self.assertLess(target_1, graph.schema)
# graph appends its predicates
- self.assertEqual(graph.schema, target_1 + schema.Schema.from_string('''
+ self.assertEqual(graph.schema, target_1 + 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 bsm: <http://bsfs.ai/schema/Meta#>
- xsd:integer rdfs:subClassOf bsfs:Literal .
- bsm:t_created rdfs:subClassOf bsfs:Predicate ;
+ prefix bsfs: <https://schema.bsfs.io/core/>
+ prefix bsn: <https://schema.bsfs.io/core/Node#>
+ prefix bsl: <https://schema.bsfs.io/core/Literal/>
+ bsl:Number rdfs:subClassOf bsfs:Literal .
+ xsd:float rdfs:subClassOf bsl:Number .
+ bsn:t_created rdfs:subClassOf bsfs:Predicate ;
rdfs:domain bsfs:Node ;
- rdfs:range xsd:integer ;
+ rdfs:range xsd:float ;
bsfs:unique "true"^^xsd:boolean .
'''))
# can overwrite the current schema
- target_2 = schema.Schema.from_string('''
+ target_2 = 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#>
+ prefix bsfs: <http://schema.bsfs.io/core/>
+ prefix bse: <http://schema.bsfs.io/core/Node/Entity#>
+ prefix bsl: <https://schema.bsfs.io/core/Literal/>
bsfs:Entity rdfs:subClassOf bsfs:Node .
xsd:string rdfs:subClassOf bsfs:Literal .
- xsd:integer rdfs:subClassOf bsfs:Literal .
+ bsl:Number rdfs:subClassOf bsfs:Literal .
+ xsd:integer rdfs:subClassOf bsl:Number .
bse:filename rdfs:subClassOf bsfs:Predicate ;
rdfs:domain bsfs:Entity ;
@@ -180,18 +197,147 @@ class TestGraph(unittest.TestCase):
# new schema is applied
self.assertLess(target_2, graph.schema)
# graph appends its predicates
- self.assertEqual(graph.schema, target_2 + schema.Schema.from_string('''
+ self.assertEqual(graph.schema, target_2 + 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 bsm: <http://bsfs.ai/schema/Meta#>
- xsd:integer rdfs:subClassOf bsfs:Literal .
- bsm:t_created rdfs:subClassOf bsfs:Predicate ;
+ prefix bsfs: <https://schema.bsfs.io/core/>
+ prefix bsn: <https://schema.bsfs.io/core/Node#>
+ prefix bsl: <https://schema.bsfs.io/core/Literal/>
+ bsl:Number rdfs:subClassOf bsfs:Literal .
+ xsd:float rdfs:subClassOf bsl:Number .
+ bsn:t_created rdfs:subClassOf bsfs:Predicate ;
rdfs:domain bsfs:Node ;
- rdfs:range xsd:integer ;
+ rdfs:range xsd:float ;
bsfs:unique "true"^^xsd:boolean .
'''))
+ def test_get(self):
+ # setup
+ graph = Graph(self.backend, self.ac)
+ graph.migrate(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: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')
+
+ # invalid query raises exception
+ self.assertRaises(errors.ConsistencyError, graph.get, ns.bsfs.Entity, ast.filter.Any(ns.bse.tag, ast.filter.Equals('hello world')))
+
+ # get 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)
+
+ # query can be None
+ self.assertEqual(graph.get(ns.bsfs.Entity, None), ents)
+
+ def test_sorted(self):
+ # setup
+ graph = Graph(self.backend, self.ac)
+ graph.migrate(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: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 = [
+ # default is alphabetical order
+ graph.node(ns.bsfs.Entity, URI('http://example.com/entity#1234')),
+ graph.node(ns.bsfs.Entity, 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
+ reduce(operator.add, 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')
+
+ # invalid query raises exception
+ self.assertRaises(errors.ConsistencyError, list, graph.sorted(ns.bsfs.Entity, ast.filter.Any(ns.bse.tag, ast.filter.Equals('hello world'))))
+
+ # get returns nodes
+ self.assertListEqual(list(graph.sorted(ns.bsfs.Entity, ast.filter.Any(ns.bse.tag, ast.filter.Is(tags)))), ents)
+ self.assertListEqual(list(graph.sorted(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.assertListEqual(list(graph.sorted(ns.bsfs.Node, ast.filter.Any(ns.bse.comment, ast.filter.StartsWith('foo')))), [
+ graph.node(ns.bsfs.Node, URI('http://example.com/entity#1234')),
+ graph.node(ns.bsfs.Node, URI('http://example.com/tag#1234')),
+ ])
+ self.assertListEqual(list(graph.sorted(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)
+
+ # query can be None
+ self.assertListEqual(list(graph.sorted(ns.bsfs.Entity, None)), ents)
+
+
+ def test_all(self):
+ graph = Graph(self.backend, self.ac)
+ # resulting nodes can be empty
+ self.assertEqual(graph.all(ns.bsfs.Entity),
+ Nodes(self.backend, self.ac, graph.schema.node(ns.bsfs.Entity), set()))
+ # resulting nodes contains all nodes of the respective type
+ guids = {URI('http://example.com/me/entity#1234'), URI('http://example.com/me/entity#4321')}
+ self.backend.create(graph.schema.node(ns.bsfs.Entity), guids)
+ self.assertEqual(graph.all(ns.bsfs.Entity),
+ Nodes(self.backend, self.ac, graph.schema.node(ns.bsfs.Entity), guids))
+ # node_type must be in the schema
+ self.assertRaises(KeyError, graph.all, ns.bsfs.Invalid)
+
+
## main ##