# 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 # objects to test from bsfs.graph.graph import Graph ## code ## ns.bse = ns.bsfs.Entity() class TestGraph(unittest.TestCase): def setUp(self): self.backend = SparqlStore.Open() self.backend.schema = schema.from_string(''' prefix rdfs: prefix bsfs: 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.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.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, 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.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.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.ac)) self.assertEqual(hash(graph), hash(Graph(self.backend, self.ac))) # equality respects backend 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.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.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.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.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.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.ac) # argument must be a schema class Foo(): pass self.assertRaises(TypeError, graph.migrate, 'hello world') self.assertRaises(TypeError, graph.migrate, 1234) self.assertRaises(TypeError, graph.migrate, Foo()) # cannot append inconsistent schema self.assertRaises(errors.ConsistencyError, graph.migrate, schema.Schema({}, { schema.Node(ns.bsfs.Entity, schema.Node(ns.bsfs.Intermediate, schema.Node(ns.bsfs.Node, None)))}), append=True) # cannot migrate to inconsistent schema self.assertRaises(errors.ConsistencyError, graph.migrate, schema.Schema({}, { schema.Node(ns.bsfs.Entity, schema.Node(ns.bsfs.Intermediate, schema.Node(ns.bsfs.Node, None)))}), append=False) # can migrate to compatible schema target_1 = schema.from_string(''' prefix rdfs: prefix xsd: prefix bsfs: prefix bse: prefix bsl: bsfs:Entity rdfs:subClassOf bsfs:Node . xsd:string 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 ; 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 . ''') graph.migrate(target_1) # new schema is applied self.assertLess(target_1, graph.schema) # graph appends its predicates self.assertEqual(graph.schema, target_1 + schema.from_string(''' prefix rdfs: prefix xsd: prefix bsfs: prefix bsn: prefix bsl: 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:float ; bsfs:unique "true"^^xsd:boolean . ''')) # can overwrite the current schema target_2 = schema.from_string(''' prefix rdfs: prefix xsd: prefix bsfs: prefix bse: prefix bsl: bsfs:Entity rdfs:subClassOf bsfs:Node . xsd:string 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 ; rdfs:range xsd:string ; bsfs:unique "false"^^xsd:boolean . bse:author rdfs:subClassOf bsfs:Predicate ; rdfs:domain bsfs:Entity ; rdfs:range xsd:string ; bsfs:unique "true"^^xsd:boolean . ''') graph.migrate(target_2, append=False) # append overwrites existing predicates self.assertFalse(target_1 <= graph.schema) # new schema is applied self.assertLess(target_2, graph.schema) # graph appends its predicates self.assertEqual(graph.schema, target_2 + schema.from_string(''' prefix rdfs: prefix xsd: prefix bsfs: prefix bsn: prefix bsl: 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:float ; bsfs:unique "true"^^xsd:boolean . ''')) def test_get(self): # setup graph = Graph(self.backend, self.ac) graph.migrate(schema.from_string(''' prefix rdfs: prefix xsd: prefix bsfs: prefix bse: 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: prefix xsd: prefix bsfs: prefix bse: 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 ## if __name__ == '__main__': unittest.main() ## EOF ##