diff options
Diffstat (limited to 'test/schema/test_schema.py')
-rw-r--r-- | test/schema/test_schema.py | 616 |
1 files changed, 616 insertions, 0 deletions
diff --git a/test/schema/test_schema.py b/test/schema/test_schema.py new file mode 100644 index 0000000..2dc26e8 --- /dev/null +++ b/test/schema/test_schema.py @@ -0,0 +1,616 @@ +""" + +Part of the tagit test suite. +A copy of the license is provided with the project. +Author: Matthias Baumgartner, 2022 +""" +# imports +import operator +import unittest + +# bsfs imports +from bsfs.namespace import ns +from bsfs.schema import types +from bsfs.utils import errors + +# objects to test +from bsfs.schema.schema import Schema + + +## code ## + +class TestSchema(unittest.TestCase): + + def setUp(self): + self.schema_str = ''' + 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 . + bsfs:Image rdfs:subClassOf bsfs:Entity . + bsfs:Unused rdfs:subClassOf bsfs:Node . + + xsd:string rdfs:subClassOf bsfs:Literal . + xsd:integer rdfs:subClassOf bsfs:Literal . + xsd:boolean rdfs:subClassOf bsfs:Literal . + + bse:tag rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsfs:Entity ; + rdfs:range bsfs:Tag ; + bsfs:unique "false"^^xsd:boolean . + + bse:group rdfs:subClassOf bse:tag ; + rdfs:domain bsfs:Image ; + 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 "true"^^xsd:boolean . + + ''' + # nodes + self.n_root = types.Node(ns.bsfs.Node, None) + self.n_ent = types.Node(ns.bsfs.Entity, types.Node(ns.bsfs.Node, None)) + self.n_img = types.Node(ns.bsfs.Image, types.Node(ns.bsfs.Entity, types.Node(ns.bsfs.Node, None))) + self.n_tag = types.Node(ns.bsfs.Tag, types.Node(ns.bsfs.Node, None)) + self.n_unused = types.Node(ns.bsfs.Unused, types.Node(ns.bsfs.Node, None)) + self.nodes = [self.n_root, self.n_ent, self.n_img, self.n_tag, self.n_unused] + + # literals + self.l_root = types.Literal(ns.bsfs.Literal, None) + self.l_string = types.Literal(ns.xsd.string, types.Literal(ns.bsfs.Literal, None)) + self.l_integer = types.Literal(ns.xsd.integer, types.Literal(ns.bsfs.Literal, None)) + self.l_unused = types.Literal(ns.xsd.boolean, types.Literal(ns.bsfs.Literal, None)) + self.literals = [self.l_root, self.l_string, self.l_integer, self.l_unused] + + # predicates + self.p_root = types.Predicate(ns.bsfs.Predicate, None, types.Node(ns.bsfs.Node, None), None, False) + self.p_tag = self.p_root.get_child(ns.bse.tag, self.n_ent, self.n_tag, False) + self.p_group = self.p_tag.get_child(ns.bse.group, self.n_img, self.n_tag, False) + self.p_comment = self.p_root.get_child(ns.bse.comment, self.n_root, self.l_string, True) + self.predicates = [self.p_root, self.p_tag, self.p_group, self.p_comment] + + def test_construction(self): + # nodes and literals are optional + schema = Schema(self.predicates) + self.assertSetEqual(set(schema.nodes()), {self.n_root, self.n_ent, self.n_img, self.n_tag}) + self.assertSetEqual(set(schema.literals()), {self.l_root, self.l_string}) + self.assertSetEqual(set(schema.predicates()), set(self.predicates)) + + # predicates, nodes, and literals are respected + schema = Schema(self.predicates, self.nodes, self.literals) + self.assertSetEqual(set(schema.nodes()), set(self.nodes)) + self.assertSetEqual(set(schema.literals()), set(self.literals)) + self.assertSetEqual(set(schema.predicates()), set(self.predicates)) + + # nodes are complete (w/o unused) + schema = Schema(self.predicates, None, self.literals) + self.assertSetEqual(set(schema.nodes()), {self.n_root, self.n_ent, self.n_img, self.n_tag}) + schema = Schema(self.predicates, [], self.literals) + self.assertSetEqual(set(schema.nodes()), {self.n_root, self.n_ent, self.n_img, self.n_tag}) + schema = Schema(self.predicates, [self.n_img, self.n_tag], self.literals) + self.assertSetEqual(set(schema.nodes()), {self.n_root, self.n_ent, self.n_img, self.n_tag}) + schema = Schema(self.predicates, [self.n_unused], self.literals) + self.assertSetEqual(set(schema.nodes()), set(self.nodes)) + + # literals are complete + schema = Schema(self.predicates, self.nodes, None) + self.assertSetEqual(set(schema.literals()), {self.l_root, self.l_string}) + schema = Schema(self.predicates, self.nodes, []) + self.assertSetEqual(set(schema.literals()), {self.l_root, self.l_string}) + schema = Schema(self.predicates, self.nodes, [self.l_string]) + self.assertSetEqual(set(schema.literals()), {self.l_root, self.l_string}) + schema = Schema(self.predicates, self.nodes, [self.l_integer]) + self.assertSetEqual(set(schema.literals()), {self.l_root, self.l_string, self.l_integer}) + schema = Schema(self.predicates, self.nodes, [self.l_integer, self.l_unused]) + self.assertSetEqual(set(schema.literals()), set(self.literals)) + + # predicates are complete + schema = Schema([], self.nodes, self.literals) + self.assertSetEqual(set(schema.predicates()), set()) + schema = Schema([self.p_group], self.nodes, self.literals) + self.assertSetEqual(set(schema.predicates()), {self.p_root, self.p_tag, self.p_group}) + schema = Schema([self.p_group, self.p_comment], self.nodes, self.literals) + self.assertSetEqual(set(schema.predicates()), set(self.predicates)) + + # node uris must be unique + self.assertRaises(errors.ConsistencyError, Schema, self.predicates, + self.nodes + [types.Node(ns.bsfs.Entity, None)], self.literals) + self.assertRaises(errors.ConsistencyError, Schema, self.predicates, + self.nodes + [types.Node(ns.bsfs.Entity, types.Node(ns.bsfs.Foo, None))], self.literals) + self.assertRaises(errors.ConsistencyError, Schema, self.predicates, + self.nodes + [types.Node(ns.bsfs.Entity, self.n_img)], self.literals) + self.assertRaises(errors.ConsistencyError, Schema, self.predicates, + [types.Node(ns.bsfs.Entity, self.n_img)], self.literals) + + # literal uris must be unique + self.assertRaises(errors.ConsistencyError, Schema, self.predicates, self.nodes, + self.literals + [types.Literal(ns.xsd.string, None)]) + self.assertRaises(errors.ConsistencyError, Schema, self.predicates, self.nodes, + self.literals + [types.Literal(ns.xsd.string, types.Literal(ns.bsfs.Foo, None))]) + self.assertRaises(errors.ConsistencyError, Schema, self.predicates, self.nodes, + self.literals + [types.Literal(ns.xsd.string, self.l_integer)]) + self.assertRaises(errors.ConsistencyError, Schema, self.predicates, self.nodes, + [types.Literal(ns.xsd.string, self.l_integer)]) + + # predicate uris must be unique + self.assertRaises(errors.ConsistencyError, Schema, + self.predicates + [types.Predicate(ns.bse.tag, self.p_root, self.n_root, self.n_tag, False)]) + self.assertRaises(errors.ConsistencyError, Schema, + self.predicates + [types.Predicate(ns.bse.tag, self.p_root, self.n_ent, self.n_img, False)]) + self.assertRaises(errors.ConsistencyError, Schema, + self.predicates + [types.Predicate(ns.bse.tag, self.p_root, self.n_ent, self.n_tag, True)]) + self.assertRaises(errors.ConsistencyError, Schema, + self.predicates + [types.Predicate(ns.bse.tag, None, self.n_ent, self.n_tag, False)]) + + # uris must be unique across nodes, literals, and predicates + self.assertRaises(errors.ConsistencyError, Schema, + {}, {types.Node(ns.bsfs.Foo, None)}, {types.Node(ns.bsfs.Foo, None)}) + self.assertRaises(errors.ConsistencyError, Schema, + {types.Predicate(ns.bsfs.Foo, None, types.Node(ns.bsfs.Node, None), None, False)}, {}, {types.Node(ns.bsfs.Foo, None)}) + self.assertRaises(errors.ConsistencyError, Schema, + {types.Predicate(ns.bsfs.Foo, None, types.Node(ns.bsfs.Node, None), None, False)}, {types.Node(ns.bsfs.Foo, None)}, {}) + self.assertRaises(errors.ConsistencyError, Schema, + {types.Predicate(ns.bsfs.Foo, None, types.Node(ns.bsfs.Node, None), None, False)}, {types.Node(ns.bsfs.Foo, None)}, {types.Node(ns.bsfs.Foo, None)}) + + def test_str(self): + self.assertEqual(str(Schema([])), 'Schema()') + self.assertEqual(str(Schema([], [], [])), 'Schema()') + self.assertEqual(str(Schema(self.predicates, self.nodes, self.literals)), 'Schema()') + self.assertEqual(repr(Schema([])), 'Schema([], [], [])') + self.assertEqual(repr(Schema([], [], [])), 'Schema([], [], [])') + n = [ns.bsfs.Entity, ns.bsfs.Image, ns.bsfs.Node, ns.bsfs.Tag, ns.bsfs.Unused] + l = [ns.bsfs.Literal, ns.xsd.boolean, ns.xsd.integer, ns.xsd.string] + p = [ns.bse.comment, ns.bse.group, ns.bse.tag, ns.bsfs.Predicate] + self.assertEqual(repr(Schema(self.predicates, self.nodes, self.literals)), f'Schema({n}, {l}, {p})') + + def test_equality(self): + schema = Schema(self.predicates, self.nodes, self.literals) + # instance is equal to itself + self.assertEqual(schema, schema) + self.assertEqual(hash(schema), hash(schema)) + # instance is equal to a clone + self.assertEqual(schema, Schema(self.predicates, self.nodes, self.literals)) + self.assertEqual(hash(schema), hash(Schema(self.predicates, self.nodes, self.literals))) + # equality respects nodes + self.assertNotEqual(schema, + Schema(self.predicates, [self.n_root, self.n_ent, self.n_img, self.n_tag], self.literals)) + self.assertNotEqual(hash(schema), + hash(Schema(self.predicates, [self.n_root, self.n_ent, self.n_img, self.n_tag], self.literals))) + self.assertNotEqual(schema, + Schema(self.predicates, self.nodes + [types.Node(ns.bsfs.Document, self.n_ent)], self.literals)) + self.assertNotEqual(hash(schema), + hash(Schema(self.predicates, self.nodes + [types.Node(ns.bsfs.Document, self.n_ent)], self.literals))) + # equality respects literals + self.assertNotEqual(schema, + Schema(self.predicates, self.nodes, [self.l_root, self.l_string, self.l_integer])) + self.assertNotEqual(hash(schema), + hash(Schema(self.predicates, self.nodes, [self.l_root, self.l_string, self.l_integer]))) + self.assertNotEqual(schema, + Schema(self.predicates, self.nodes, self.literals + [types.Literal(ns.xsd.number, self.l_root)])) + self.assertNotEqual(hash(schema), + hash(Schema(self.predicates, self.nodes, self.literals + [types.Literal(ns.xsd.number, self.l_root)]))) + # equality respects predicates + self.assertNotEqual(schema, + Schema([self.p_group, self.p_tag, self.p_root], self.nodes, self.literals)) + self.assertNotEqual(hash(schema), + hash(Schema([self.p_group, self.p_tag, self.p_root], self.nodes, self.literals))) + self.assertNotEqual(schema, + Schema(self.predicates + [self.p_root.get_child(ns.bse.filesize, self.n_ent, self.l_integer)], self.nodes, self.literals)) + self.assertNotEqual(hash(schema), + hash(Schema(self.predicates + [self.p_root.get_child(ns.bse.filesize, self.n_ent, self.l_integer)], self.nodes, self.literals))) + + def test_diff(self): + # difference can be empty + diff = Schema({self.p_tag}).diff(Schema({self.p_group})) + self.assertSetEqual(set(diff.nodes), set()) + self.assertSetEqual(set(diff.literals), set()) + self.assertSetEqual(set(diff.predicates), set()) + + # difference contains predicates from the LHS + diff = Schema({self.p_group}).diff(Schema({self.p_tag})) + self.assertSetEqual(set(diff.nodes), {self.n_img}) + self.assertSetEqual(set(diff.literals), set()) + self.assertSetEqual(set(diff.predicates), {self.p_group}) + + # difference does not contain predicates from the RHS + diff = Schema({self.p_tag, self.p_comment}).diff(Schema({self.p_group})) + self.assertSetEqual(set(diff.nodes), set()) + self.assertSetEqual(set(diff.literals), {self.l_root, self.l_string}) + self.assertSetEqual(set(diff.predicates), {self.p_comment}) + + # difference considers extra nodes and literals + diff = Schema({self.p_tag}, {self.n_unused}, {self.l_unused}).diff(Schema({self.p_tag})) + self.assertSetEqual(set(diff.nodes), {self.n_unused}) + self.assertSetEqual(set(diff.literals), {self.l_root, self.l_unused}) + self.assertSetEqual(set(diff.predicates), set()) + + # difference considers inconsistent types + diff = Schema({self.p_tag}, {self.n_unused}, {self.l_unused}).diff( + Schema({self.p_tag}, {types.Node(ns.bsfs.Unused, None)}, {types.Literal(ns.xsd.boolean, None)})) + self.assertSetEqual(set(diff.nodes), {self.n_unused}) + self.assertSetEqual(set(diff.literals), {self.l_root, self.l_unused}) + self.assertSetEqual(set(diff.predicates), set()) + + # __sub__ is an alias for diff + diff = Schema({self.p_comment}, {self.n_unused}, {self.l_unused}) - Schema({self.p_group}) + self.assertSetEqual(set(diff.nodes), {self.n_unused}) + self.assertSetEqual(set(diff.literals), {self.l_root, self.l_string, self.l_unused}) + self.assertSetEqual(set(diff.predicates), {self.p_comment}) + # __sub__ only accepts Schema instances + class Foo(): pass + self.assertRaises(TypeError, operator.sub, Schema({self.p_comment}, {self.n_unused}, {self.l_unused}), 1234) + self.assertRaises(TypeError, operator.sub, Schema({self.p_comment}, {self.n_unused}, {self.l_unused}), 'hello world') + self.assertRaises(TypeError, operator.sub, Schema({self.p_comment}, {self.n_unused}, {self.l_unused}), Foo()) + + def test_consistent_with(self): + # argument must be a schema + class Foo(): pass + self.assertRaises(TypeError, Schema([]).consistent_with, 1234) + self.assertRaises(TypeError, Schema([]).consistent_with, 'hello world') + self.assertRaises(TypeError, Schema([]).consistent_with, Foo()) + + # node consistency + self.assertTrue(Schema([], {self.n_ent, self.n_tag, self.n_unused}).consistent_with( + Schema(self.predicates))) + self.assertFalse(Schema([], {types.Node(ns.bsfs.Entity, None)}).consistent_with( + Schema(self.predicates))) + # order doesn't matter + self.assertTrue(Schema(self.predicates).consistent_with( + Schema([], {self.n_ent, self.n_tag, self.n_unused}))) + + # literal consistency + self.assertTrue(Schema([], [], {self.l_string, self.l_unused}).consistent_with( + Schema(self.predicates))) + self.assertFalse(Schema([], [], {types.Literal(ns.xsd.string, None)}).consistent_with( + Schema(self.predicates))) + # order doesn't matter + self.assertTrue(Schema(self.predicates).consistent_with( + Schema([], [], {self.l_string, self.l_unused}))) + + # predicate consistency + self.assertTrue(Schema({self.p_tag}).consistent_with( + Schema(self.predicates))) + self.assertFalse(Schema({types.Predicate(ns.bse.tag, None, self.n_root, self.n_root, False)}).consistent_with( + Schema(self.predicates))) + # order doesn't matter + self.assertTrue(Schema(self.predicates).consistent_with( + Schema({self.p_tag}))) + + # global consistency + self.assertFalse(Schema({types.Predicate(ns.bsfs.Entity, None, self.n_root, self.n_root, False)}).consistent_with( + Schema(self.predicates))) + self.assertFalse(Schema([], {types.Node(ns.xsd.string, None)}).consistent_with( + Schema(self.predicates))) + self.assertFalse(Schema([], [], {types.Literal(ns.bsfs.Entity, None)}).consistent_with( + Schema(self.predicates))) + + + def test_union(self): + # must provide at least one schema + self.assertRaises(TypeError, Schema.Union) + + # can pass schemas as list + self.assertEqual(Schema.Union([Schema({self.p_tag})]), Schema({self.p_tag})) + self.assertEqual(Schema.Union([Schema({self.p_tag}), Schema({self.p_comment})]), + Schema({self.p_tag, self.p_comment})) + + # can pass schemas as arguments + self.assertEqual(Schema.Union(Schema({self.p_tag})), Schema({self.p_tag})) + self.assertEqual(Schema.Union(Schema({self.p_tag}), Schema({self.p_comment})), + Schema({self.p_tag, self.p_comment})) + + # cannot mix the two argument passing styles + self.assertRaises(TypeError, Schema.Union, [Schema(self.predicates)], Schema(self.predicates)) + + # all arguments must be Schema instances + self.assertRaises(TypeError, Schema.Union, Schema(self.predicates), 1234) + self.assertRaises(TypeError, Schema.Union, Schema(self.predicates), 1234, Schema(self.predicates)) + self.assertRaises(TypeError, Schema.Union, Schema(self.predicates), 'hello world') + + # Union merges predicates, nodes, and literals + self.assertEqual(Schema.Union( + Schema({self.p_comment}, {self.n_unused}, {}), + Schema({self.p_group}, {self.n_img}, {self.l_unused})), + Schema({self.p_comment, self.p_group}, {self.n_img, self.n_unused}, {self.l_unused})) + + # Union does not accept inconsistent nodes + self.assertRaises(errors.ConsistencyError, Schema.Union, Schema(self.predicates), + Schema({}, {types.Node(ns.bsfs.Entity, None)})) + self.assertRaises(errors.ConsistencyError, Schema.Union, Schema({}, {self.n_ent}), + Schema({}, {types.Node(ns.bsfs.Entity, None)})) + self.assertRaises(errors.ConsistencyError, Schema.Union, Schema({}, {self.n_ent}), + Schema({}, {}, {types.Literal(ns.bsfs.Entity, None)})) + + # Union does not accept inconsistent literals + self.assertRaises(errors.ConsistencyError, Schema.Union, Schema(self.predicates), + Schema({}, {}, {types.Literal(ns.xsd.string, None)})) + self.assertRaises(errors.ConsistencyError, Schema.Union, Schema({}, {}, {self.l_string}), + Schema({}, {}, {types.Literal(ns.xsd.string, None)})) + self.assertRaises(errors.ConsistencyError, Schema.Union, Schema({}, {}, {self.l_string}), + Schema({}, {types.Node(ns.xsd.string, None)})) + + # Union does not accept inconsistent predicates + self.assertRaises(errors.ConsistencyError, Schema.Union, Schema({self.p_tag}), + Schema({types.Predicate(ns.bse.tag, None, self.n_ent, self.n_tag, False)})) + self.assertRaises(errors.ConsistencyError, Schema.Union, Schema({self.p_tag}), + Schema({}, {types.Node(ns.bse.tag, None)})) + + # union is an alias for Union + self.assertEqual(Schema({self.p_comment}, {self.n_unused}, {}).union( + Schema({self.p_group}, {self.n_img}, {self.l_unused})), + Schema({self.p_comment, self.p_group}, {self.n_img, self.n_unused}, {self.l_unused})) + # union only accepts Schema instances + class Foo(): pass + self.assertRaises(TypeError, Schema({self.p_comment}, {self.n_unused}, {}).union, 1234) + self.assertRaises(TypeError, Schema({self.p_comment}, {self.n_unused}, {}).union, 'hello world') + self.assertRaises(TypeError, Schema({self.p_comment}, {self.n_unused}, {}).union, Foo()) + + # __add__ is an alias for Union + self.assertEqual(Schema({self.p_comment}, {self.n_unused}, {}) + Schema({self.p_group}, {self.n_img}, {self.l_unused}), + Schema({self.p_comment, self.p_group}, {self.n_img, self.n_unused}, {self.l_unused})) + # __add__ only accepts Schema instances + class Foo(): pass + self.assertRaises(TypeError, operator.add, Schema({self.p_comment}, {self.n_unused}, {}), 1234) + self.assertRaises(TypeError, operator.add, Schema({self.p_comment}, {self.n_unused}, {}), 'hello world') + self.assertRaises(TypeError, operator.add, Schema({self.p_comment}, {self.n_unused}, {}), Foo()) + + # __or__ is an alias for Union + self.assertEqual(Schema({self.p_comment}, {self.n_unused}, {}) | Schema({self.p_group}, {self.n_img}, {self.l_unused}), + Schema({self.p_comment, self.p_group}, {self.n_img, self.n_unused}, {self.l_unused})) + # __or__ only accepts Schema instances + class Foo(): pass + self.assertRaises(TypeError, operator.or_, Schema({self.p_comment}, {self.n_unused}, {}), 1234) + self.assertRaises(TypeError, operator.or_, Schema({self.p_comment}, {self.n_unused}, {}), 'hello world') + self.assertRaises(TypeError, operator.or_, Schema({self.p_comment}, {self.n_unused}, {}), Foo()) + + def test_type_getters(self): + schema = Schema(self.predicates, self.nodes, self.literals) + # nodes + self.assertEqual(self.n_root, schema.node(ns.bsfs.Node)) + self.assertEqual(self.n_ent, schema.node(ns.bsfs.Entity)) + self.assertEqual(self.n_img, schema.node(ns.bsfs.Image)) + self.assertRaises(KeyError, schema.node, ns.bsfs.Document) + self.assertRaises(KeyError, schema.node, self.n_root) + # literals + self.assertEqual(self.l_root, schema.literal(ns.bsfs.Literal)) + self.assertEqual(self.l_string, schema.literal(ns.xsd.string)) + self.assertEqual(self.l_integer, schema.literal(ns.xsd.integer)) + self.assertRaises(KeyError, schema.literal, ns.xsd.number) + self.assertRaises(KeyError, schema.literal, self.l_root) + # predicates + self.assertEqual(self.p_root, schema.predicate(ns.bsfs.Predicate)) + self.assertEqual(self.p_tag, schema.predicate(ns.bse.tag)) + self.assertEqual(self.p_group, schema.predicate(ns.bse.group)) + self.assertRaises(KeyError, schema.predicate, ns.bse.mimetype) + self.assertRaises(KeyError, schema.predicate, self.p_root) + + def test_list_getters(self): + schema = Schema(self.predicates, self.nodes, self.literals) + self.assertSetEqual(set(self.nodes), set(schema.nodes())) + self.assertSetEqual(set(self.literals), set(schema.literals())) + self.assertSetEqual(set(self.predicates), set(schema.predicates())) + + def test_has(self): + schema = Schema(self.predicates, self.nodes, self.literals) + # nodes + self.assertTrue(schema.has_node(ns.bsfs.Node)) + self.assertTrue(schema.has_node(ns.bsfs.Entity)) + self.assertTrue(schema.has_node(ns.bsfs.Image)) + self.assertFalse(schema.has_node(ns.bsfs.Document)) + self.assertFalse(schema.has_node(self.n_root)) + # literals + self.assertTrue(schema.has_literal(ns.bsfs.Literal)) + self.assertTrue(schema.has_literal(ns.xsd.string)) + self.assertTrue(schema.has_literal(ns.xsd.integer)) + self.assertFalse(schema.has_literal(ns.xsd.number)) + self.assertFalse(schema.has_literal(self.l_root)) + # predicates + self.assertTrue(schema.has_predicate(ns.bsfs.Predicate)) + self.assertTrue(schema.has_predicate(ns.bse.tag)) + self.assertTrue(schema.has_predicate(ns.bse.group)) + self.assertFalse(schema.has_predicate(ns.bse.mimetype)) + self.assertFalse(schema.has_predicate(self.p_root)) + + def test_empty(self): + self.assertEqual(Schema.Empty(), Schema( + [types.Predicate(ns.bsfs.Predicate, None, types.Node(ns.bsfs.Node, None), None, False)], + [types.Node(ns.bsfs.Node, None)], + [types.Literal(ns.bsfs.Literal, None)], + )) + + def test_from_string(self): + # from_string creates a schema + self.assertEqual( + Schema(self.predicates, self.nodes, self.literals), + Schema.from_string(self.schema_str)) + + # schema contains at least the root types + self.assertEqual(Schema.from_string(''), Schema({self.p_root}, {self.n_root}, {self.l_root})) + + # custom example + self.assertEqual( + Schema({types.Predicate(ns.bsfs.Predicate, None, self.n_root, None, False).get_child( + ns.bse.filename, self.n_ent, self.l_string, False)}), + 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 . + xsd:string rdfs:subClassOf bsfs:Literal . + + bse:filename rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsfs:Entity ; + rdfs:range xsd:string ; + bsfs:unique "false"^^xsd:boolean . + ''')) + + # all nodes must be defined + self.assertRaises(errors.ConsistencyError, 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#> + + xsd:string rdfs:subClassOf bsfs:Literal . + + bse:filename rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsfs:Entity ; + rdfs:range xsd:string ; + bsfs:unique "false"^^xsd:boolean . + ''') + + # all literals must be defined + self.assertRaises(errors.ConsistencyError, 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 . + + bse:filename rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsfs:Entity ; + rdfs:range xsd:string ; + bsfs:unique "false"^^xsd:boolean . + ''') + + # must not have circular dependencies + self.assertRaises(errors.ConsistencyError, Schema.from_string, ''' + prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> + prefix bsfs: <http://bsfs.ai/schema/> + bsfs:Entity rdfs:subClassOf bsfs:Node . + # ah, a nice circular dependency + bsfs:Entity rdfs:subClassOf bsfs:Document . + bsfs:Document rdfs:subClassOf bsfs:Entity . + bsfs:PDF rdfs:subClassOf bsfs:Document . + ''') + + # range must be a node or literal + self.assertRaises(errors.ConsistencyError, 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 . + + bse:filename rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsfs:Entity ; + rdfs:range xsd:string ; + bsfs:unique "false"^^xsd:boolean . + ''') + self.assertRaises(errors.ConsistencyError, 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 . + + bse:filename rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsfs:Entity ; + rdfs:range bsfs:Foo ; + bsfs:unique "false"^^xsd:boolean . + ''') + self.assertRaises(errors.ConsistencyError, 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 . + + bse:filename rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsfs:Entity ; + rdfs:range bsfs:Predicate ; + bsfs:unique "false"^^xsd:boolean . + ''') + + # must be consistent + self.assertRaises(errors.ConsistencyError, 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/> + + bsfs:Entity rdfs:subClassOf bsfs:Node . + bsfs:Document rdfs:subClassOf bsfs:Node . + bsfs:Document rdfs:subClassOf bsfs:Entity. + ''') + self.assertRaises(errors.ConsistencyError, 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/> + + xsd:string rdfs:subClassOf bsfs:Literal . + xsd:name rdfs:subClassOf bsfs:Literal . + xsd:name rdfs:subClassOf xsd:string . + ''') + self.assertRaises(errors.ConsistencyError, 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 . + + bse:foo rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsfs:Node ; + rdfs:range bsfs:Node ; + bsfs:unique "false"^^xsd:boolean . + + bse:foo rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsfs:Entity . + + ''') + self.assertRaises(errors.ConsistencyError, 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 . + + bse:foo rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsfs:Node ; + rdfs:range bsfs:Node ; + bsfs:unique "false"^^xsd:boolean . + + bse:foo rdfs:subClassOf bsfs:Predicate ; + rdfs:range bsfs:Entity . + + ''') + self.assertRaises(errors.ConsistencyError, 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 . + + bse:foo rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsfs:Node ; + rdfs:range bsfs:Node ; + bsfs:unique "false"^^xsd:boolean . + + bse:foo rdfs:subClassOf bsfs:Predicate ; + bsfs:unique "true"^^xsd:boolean . + + ''') + + + +## main ## + +if __name__ == '__main__': + unittest.main() + +## EOF ## |