diff options
author | Matthias Baumgartner <dev@igsor.net> | 2023-03-05 19:22:58 +0100 |
---|---|---|
committer | Matthias Baumgartner <dev@igsor.net> | 2023-03-05 19:22:58 +0100 |
commit | a35b33f4f1ddcf6f1bb8ab0f41b87bf2b847f11d (patch) | |
tree | fb220da28bb7248ebf37ce09af5de88f2c1aaad4 /test | |
parent | 7582c280ad5324a2f0427999911c7e7abc14a6ab (diff) | |
parent | af81318ae9311fd0b0e16949cef3cfaf7996970b (diff) | |
download | bsie-release.tar.gz bsie-release.tar.bz2 bsie-release.zip |
Diffstat (limited to 'test')
55 files changed, 2380 insertions, 557 deletions
diff --git a/test/apps/test_index.py b/test/apps/test_index.py index 9cdc656..6927044 100644 --- a/test/apps/test_index.py +++ b/test/apps/test_index.py @@ -1,16 +1,15 @@ -""" -Part of the bsie test suite. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 -""" -# imports +# standard imports import contextlib import io import os -import rdflib +import tempfile import unittest +# external imports +import rdflib +import yaml + # bsie imports from bsie.utils import ns @@ -21,134 +20,283 @@ from bsie.apps.index import main ## code ## class TestIndex(unittest.TestCase): + def setUp(self): + config = { + 'ReaderBuilder': {}, + 'ExtractorBuilder': [ + {'bsie.extractor.preview.Preview': { + 'max_sides': [50], + }}, + {'bsie.extractor.generic.path.Path': {}}, + {'bsie.extractor.generic.constant.Constant': { + 'schema': ''' + bse:author rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsn:Entity ; + rdfs:range xsd:string ; + bsfs:unique "true"^^xsd:boolean . + ''', + 'tuples': [['https://schema.bsfs.io/ie/Node/Entity#author', 'Me, myself, and I']], + }}, + {'bsie.extractor.image.colors_spatial.ColorsSpatial': { + 'width': 2, + 'height': 2, + 'exp': 2, + }}, + ] + } + # create config file + _, self.config_path = tempfile.mkstemp(prefix='bsie-test-', suffix='.yaml') + with open(self.config_path, 'wt') as cfile: + yaml.dump(config, cfile) + + def tearDown(self): + if os.path.exists(self.config_path): + os.unlink(self.config_path) + + def test_disclaimer(self): + print('Please wait, this test will take about 25 seconds') + + def test_main_invalid(self): + outbuf = io.StringIO() + with contextlib.redirect_stdout(outbuf): + bsfs = main(['--config', self.config_path, os.path.join(os.path.dirname(__file__), 'inexistent-file.t')]) + self.assertEqual(outbuf.getvalue().strip(), '') + def test_main(self): bsfs = main([ + '--config', + self.config_path, '-r', - '--user', 'http://example.com/me', + '--host', 'http://example.com', + '--user', 'me', os.path.join(os.path.dirname(__file__), 'testdir'), os.path.join(os.path.dirname(__file__), 'testfile'), ]) - prefix = 'http://example.com/me/file#' + pre_file = 'http://example.com/me/file#' + pre_preview = 'http://example.com/me/preview#' self.assertTrue(set(bsfs._backend._graph).issuperset({ - (rdflib.URIRef(prefix + '2f4109b40107cc50e0884755a1a961ed126887e49b8dbaf0e146b2e226aa6647'), rdflib.RDF.type, rdflib.URIRef(ns.bsfs.File)), - (rdflib.URIRef(prefix + '2f4109b40107cc50e0884755a1a961ed126887e49b8dbaf0e146b2e226aa6647'), rdflib.URIRef(ns.bse.author), rdflib.Literal('Me, myself, and I', datatype=rdflib.XSD.string)), - (rdflib.URIRef(prefix + '2f4109b40107cc50e0884755a1a961ed126887e49b8dbaf0e146b2e226aa6647'), rdflib.URIRef(ns.bse.filename), rdflib.Literal('alpha_second', datatype=rdflib.XSD.string)), - (rdflib.URIRef(prefix + '2f4109b40107cc50e0884755a1a961ed126887e49b8dbaf0e146b2e226aa6647'), rdflib.URIRef(ns.bse.filesize), rdflib.Literal('696', datatype=rdflib.XSD.integer)), - (rdflib.URIRef(prefix + '441f3d10c8ff489fe8e33e639606512f6c463151cc429de7e554b9af670c2ece'), rdflib.RDF.type, rdflib.URIRef(ns.bsfs.File)), - (rdflib.URIRef(prefix + '441f3d10c8ff489fe8e33e639606512f6c463151cc429de7e554b9af670c2ece'), rdflib.URIRef(ns.bse.author), rdflib.Literal('Me, myself, and I', datatype=rdflib.XSD.string)), - (rdflib.URIRef(prefix + '441f3d10c8ff489fe8e33e639606512f6c463151cc429de7e554b9af670c2ece'), rdflib.URIRef(ns.bse.filename), rdflib.Literal('omega_second', datatype=rdflib.XSD.string)), - (rdflib.URIRef(prefix + '441f3d10c8ff489fe8e33e639606512f6c463151cc429de7e554b9af670c2ece'), rdflib.URIRef(ns.bse.filesize), rdflib.Literal('503', datatype=rdflib.XSD.integer)), - (rdflib.URIRef(prefix + '69b98ecf7aff3e95b09688ba93331678eb8397817111f674c9558e6dd8f5e871'), rdflib.RDF.type, rdflib.URIRef(ns.bsfs.File)), - (rdflib.URIRef(prefix + '69b98ecf7aff3e95b09688ba93331678eb8397817111f674c9558e6dd8f5e871'), rdflib.URIRef(ns.bse.author), rdflib.Literal('Me, myself, and I', datatype=rdflib.XSD.string)), - (rdflib.URIRef(prefix + '69b98ecf7aff3e95b09688ba93331678eb8397817111f674c9558e6dd8f5e871'), rdflib.URIRef(ns.bse.filename), rdflib.Literal('td_first', datatype=rdflib.XSD.string)), - (rdflib.URIRef(prefix + '69b98ecf7aff3e95b09688ba93331678eb8397817111f674c9558e6dd8f5e871'), rdflib.URIRef(ns.bse.filesize), rdflib.Literal('911', datatype=rdflib.XSD.integer)), - (rdflib.URIRef(prefix + '78f7eb7f0d8221cdb2cb26c978fa42a11f75eb87becc768f4474134cb1e06926'), rdflib.RDF.type, rdflib.URIRef(ns.bsfs.File)), - (rdflib.URIRef(prefix + '78f7eb7f0d8221cdb2cb26c978fa42a11f75eb87becc768f4474134cb1e06926'), rdflib.URIRef(ns.bse.author), rdflib.Literal('Me, myself, and I', datatype=rdflib.XSD.string)), - (rdflib.URIRef(prefix + '78f7eb7f0d8221cdb2cb26c978fa42a11f75eb87becc768f4474134cb1e06926'), rdflib.URIRef(ns.bse.filename), rdflib.Literal('testfile', datatype=rdflib.XSD.string)), - (rdflib.URIRef(prefix + '78f7eb7f0d8221cdb2cb26c978fa42a11f75eb87becc768f4474134cb1e06926'), rdflib.URIRef(ns.bse.filesize), rdflib.Literal('885', datatype=rdflib.XSD.integer)), - (rdflib.URIRef(prefix + '80818b8ec2ee1919116dba9c8a7e0a4608313cf3b463cd88e9ed77a700dd92d3'), rdflib.RDF.type, rdflib.URIRef(ns.bsfs.File)), - (rdflib.URIRef(prefix + '80818b8ec2ee1919116dba9c8a7e0a4608313cf3b463cd88e9ed77a700dd92d3'), rdflib.URIRef(ns.bse.author), rdflib.Literal('Me, myself, and I', datatype=rdflib.XSD.string)), - (rdflib.URIRef(prefix + '80818b8ec2ee1919116dba9c8a7e0a4608313cf3b463cd88e9ed77a700dd92d3'), rdflib.URIRef(ns.bse.filename), rdflib.Literal('bar_first', datatype=rdflib.XSD.string)), - (rdflib.URIRef(prefix + '80818b8ec2ee1919116dba9c8a7e0a4608313cf3b463cd88e9ed77a700dd92d3'), rdflib.URIRef(ns.bse.filesize), rdflib.Literal('956', datatype=rdflib.XSD.integer)), - (rdflib.URIRef(prefix + '976d2ea0e58488678cc7e435fbfadabfb6eb6cf50ad51862f38f73729ed11795'), rdflib.RDF.type, rdflib.URIRef(ns.bsfs.File)), - (rdflib.URIRef(prefix + '976d2ea0e58488678cc7e435fbfadabfb6eb6cf50ad51862f38f73729ed11795'), rdflib.URIRef(ns.bse.author), rdflib.Literal('Me, myself, and I', datatype=rdflib.XSD.string)), - (rdflib.URIRef(prefix + '976d2ea0e58488678cc7e435fbfadabfb6eb6cf50ad51862f38f73729ed11795'), rdflib.URIRef(ns.bse.filename), rdflib.Literal('omega_first', datatype=rdflib.XSD.string)), - (rdflib.URIRef(prefix + '976d2ea0e58488678cc7e435fbfadabfb6eb6cf50ad51862f38f73729ed11795'), rdflib.URIRef(ns.bse.filesize), rdflib.Literal('648', datatype=rdflib.XSD.integer)), - (rdflib.URIRef(prefix + '997e2fbb7494a3818ec782d2bc87bf1cffafba6b9c0f658e4a6c18a723e944d3'), rdflib.RDF.type, rdflib.URIRef(ns.bsfs.File)), - (rdflib.URIRef(prefix + '997e2fbb7494a3818ec782d2bc87bf1cffafba6b9c0f658e4a6c18a723e944d3'), rdflib.URIRef(ns.bse.author), rdflib.Literal('Me, myself, and I', datatype=rdflib.XSD.string)), - (rdflib.URIRef(prefix + '997e2fbb7494a3818ec782d2bc87bf1cffafba6b9c0f658e4a6c18a723e944d3'), rdflib.URIRef(ns.bse.filename), rdflib.Literal('alpha_first', datatype=rdflib.XSD.string)), - (rdflib.URIRef(prefix + '997e2fbb7494a3818ec782d2bc87bf1cffafba6b9c0f658e4a6c18a723e944d3'), rdflib.URIRef(ns.bse.filesize), rdflib.Literal('754', datatype=rdflib.XSD.integer)), - (rdflib.URIRef(prefix + 'a8af899ecdab60dfaea8ec7f934053624c80a1054539e163f2c7eaa986c2777d'), rdflib.RDF.type, rdflib.URIRef(ns.bsfs.File)), - (rdflib.URIRef(prefix + 'a8af899ecdab60dfaea8ec7f934053624c80a1054539e163f2c7eaa986c2777d'), rdflib.URIRef(ns.bse.author), rdflib.Literal('Me, myself, and I', datatype=rdflib.XSD.string)), - (rdflib.URIRef(prefix + 'a8af899ecdab60dfaea8ec7f934053624c80a1054539e163f2c7eaa986c2777d'), rdflib.URIRef(ns.bse.filename), rdflib.Literal('foo_second', datatype=rdflib.XSD.string)), - (rdflib.URIRef(prefix + 'a8af899ecdab60dfaea8ec7f934053624c80a1054539e163f2c7eaa986c2777d'), rdflib.URIRef(ns.bse.filesize), rdflib.Literal('585', datatype=rdflib.XSD.integer)), - (rdflib.URIRef(prefix + 'b8fd7fba818254166a6043195004138ebda6923e012442f819a2c49671136c70'), rdflib.RDF.type, rdflib.URIRef(ns.bsfs.File)), - (rdflib.URIRef(prefix + 'b8fd7fba818254166a6043195004138ebda6923e012442f819a2c49671136c70'), rdflib.URIRef(ns.bse.author), rdflib.Literal('Me, myself, and I', datatype=rdflib.XSD.string)), - (rdflib.URIRef(prefix + 'b8fd7fba818254166a6043195004138ebda6923e012442f819a2c49671136c70'), rdflib.URIRef(ns.bse.filename), rdflib.Literal('bar_second', datatype=rdflib.XSD.string)), - (rdflib.URIRef(prefix + 'b8fd7fba818254166a6043195004138ebda6923e012442f819a2c49671136c70'), rdflib.URIRef(ns.bse.filesize), rdflib.Literal('636', datatype=rdflib.XSD.integer)), - (rdflib.URIRef(prefix + 'd43758ace82154a1cc10ca0dfef63cb20dd831f9c87edd6dc06539eefe67371d'), rdflib.RDF.type, rdflib.URIRef(ns.bsfs.File)), - (rdflib.URIRef(prefix + 'd43758ace82154a1cc10ca0dfef63cb20dd831f9c87edd6dc06539eefe67371d'), rdflib.URIRef(ns.bse.author), rdflib.Literal('Me, myself, and I', datatype=rdflib.XSD.string)), - (rdflib.URIRef(prefix + 'd43758ace82154a1cc10ca0dfef63cb20dd831f9c87edd6dc06539eefe67371d'), rdflib.URIRef(ns.bse.filename), rdflib.Literal('foo_first', datatype=rdflib.XSD.string)), - (rdflib.URIRef(prefix + 'd43758ace82154a1cc10ca0dfef63cb20dd831f9c87edd6dc06539eefe67371d'), rdflib.URIRef(ns.bse.filesize), rdflib.Literal('546', datatype=rdflib.XSD.integer)), - (rdflib.URIRef(prefix + 'd803187cbf3676ae9d38126270a6152c60431589aa3bb3824baf8954e9c097f1'), rdflib.RDF.type, rdflib.URIRef(ns.bsfs.File)), - (rdflib.URIRef(prefix + 'd803187cbf3676ae9d38126270a6152c60431589aa3bb3824baf8954e9c097f1'), rdflib.URIRef(ns.bse.author), rdflib.Literal('Me, myself, and I', datatype=rdflib.XSD.string)), - (rdflib.URIRef(prefix + 'd803187cbf3676ae9d38126270a6152c60431589aa3bb3824baf8954e9c097f1'), rdflib.URIRef(ns.bse.filename), rdflib.Literal('td_second', datatype=rdflib.XSD.string)), - (rdflib.URIRef(prefix + 'd803187cbf3676ae9d38126270a6152c60431589aa3bb3824baf8954e9c097f1'), rdflib.URIRef(ns.bse.filesize), rdflib.Literal('703', datatype=rdflib.XSD.integer)), + # files and properties + (rdflib.URIRef(pre_file + '2f4109b40107cc50e0884755a1a961ed126887e49b8dbaf0e146b2e226aa6647'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Entity)), + (rdflib.URIRef(pre_file + '2f4109b40107cc50e0884755a1a961ed126887e49b8dbaf0e146b2e226aa6647'), rdflib.URIRef(ns.bse.author), rdflib.Literal('Me, myself, and I', datatype=rdflib.XSD.string)), + (rdflib.URIRef(pre_file + '2f4109b40107cc50e0884755a1a961ed126887e49b8dbaf0e146b2e226aa6647'), rdflib.URIRef(ns.bse.filename), rdflib.Literal('alpha_second', datatype=rdflib.XSD.string)), + (rdflib.URIRef(pre_file + '441f3d10c8ff489fe8e33e639606512f6c463151cc429de7e554b9af670c2ece'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Entity)), + (rdflib.URIRef(pre_file + '441f3d10c8ff489fe8e33e639606512f6c463151cc429de7e554b9af670c2ece'), rdflib.URIRef(ns.bse.author), rdflib.Literal('Me, myself, and I', datatype=rdflib.XSD.string)), + (rdflib.URIRef(pre_file + '441f3d10c8ff489fe8e33e639606512f6c463151cc429de7e554b9af670c2ece'), rdflib.URIRef(ns.bse.filename), rdflib.Literal('omega_second', datatype=rdflib.XSD.string)), + (rdflib.URIRef(pre_file + '69b98ecf7aff3e95b09688ba93331678eb8397817111f674c9558e6dd8f5e871'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Entity)), + (rdflib.URIRef(pre_file + '69b98ecf7aff3e95b09688ba93331678eb8397817111f674c9558e6dd8f5e871'), rdflib.URIRef(ns.bse.author), rdflib.Literal('Me, myself, and I', datatype=rdflib.XSD.string)), + (rdflib.URIRef(pre_file + '69b98ecf7aff3e95b09688ba93331678eb8397817111f674c9558e6dd8f5e871'), rdflib.URIRef(ns.bse.filename), rdflib.Literal('td_first', datatype=rdflib.XSD.string)), + (rdflib.URIRef(pre_file + '78f7eb7f0d8221cdb2cb26c978fa42a11f75eb87becc768f4474134cb1e06926'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Entity)), + (rdflib.URIRef(pre_file + '78f7eb7f0d8221cdb2cb26c978fa42a11f75eb87becc768f4474134cb1e06926'), rdflib.URIRef(ns.bse.author), rdflib.Literal('Me, myself, and I', datatype=rdflib.XSD.string)), + (rdflib.URIRef(pre_file + '78f7eb7f0d8221cdb2cb26c978fa42a11f75eb87becc768f4474134cb1e06926'), rdflib.URIRef(ns.bse.filename), rdflib.Literal('testfile', datatype=rdflib.XSD.string)), + (rdflib.URIRef(pre_file + '80818b8ec2ee1919116dba9c8a7e0a4608313cf3b463cd88e9ed77a700dd92d3'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Entity)), + (rdflib.URIRef(pre_file + '80818b8ec2ee1919116dba9c8a7e0a4608313cf3b463cd88e9ed77a700dd92d3'), rdflib.URIRef(ns.bse.author), rdflib.Literal('Me, myself, and I', datatype=rdflib.XSD.string)), + (rdflib.URIRef(pre_file + '80818b8ec2ee1919116dba9c8a7e0a4608313cf3b463cd88e9ed77a700dd92d3'), rdflib.URIRef(ns.bse.filename), rdflib.Literal('bar_first', datatype=rdflib.XSD.string)), + (rdflib.URIRef(pre_file + '976d2ea0e58488678cc7e435fbfadabfb6eb6cf50ad51862f38f73729ed11795'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Entity)), + (rdflib.URIRef(pre_file + '976d2ea0e58488678cc7e435fbfadabfb6eb6cf50ad51862f38f73729ed11795'), rdflib.URIRef(ns.bse.author), rdflib.Literal('Me, myself, and I', datatype=rdflib.XSD.string)), + (rdflib.URIRef(pre_file + '976d2ea0e58488678cc7e435fbfadabfb6eb6cf50ad51862f38f73729ed11795'), rdflib.URIRef(ns.bse.filename), rdflib.Literal('omega_first', datatype=rdflib.XSD.string)), + (rdflib.URIRef(pre_file + '997e2fbb7494a3818ec782d2bc87bf1cffafba6b9c0f658e4a6c18a723e944d3'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Entity)), + (rdflib.URIRef(pre_file + '997e2fbb7494a3818ec782d2bc87bf1cffafba6b9c0f658e4a6c18a723e944d3'), rdflib.URIRef(ns.bse.author), rdflib.Literal('Me, myself, and I', datatype=rdflib.XSD.string)), + (rdflib.URIRef(pre_file + '997e2fbb7494a3818ec782d2bc87bf1cffafba6b9c0f658e4a6c18a723e944d3'), rdflib.URIRef(ns.bse.filename), rdflib.Literal('alpha_first', datatype=rdflib.XSD.string)), + (rdflib.URIRef(pre_file + 'a8af899ecdab60dfaea8ec7f934053624c80a1054539e163f2c7eaa986c2777d'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Entity)), + (rdflib.URIRef(pre_file + 'a8af899ecdab60dfaea8ec7f934053624c80a1054539e163f2c7eaa986c2777d'), rdflib.URIRef(ns.bse.author), rdflib.Literal('Me, myself, and I', datatype=rdflib.XSD.string)), + (rdflib.URIRef(pre_file + 'a8af899ecdab60dfaea8ec7f934053624c80a1054539e163f2c7eaa986c2777d'), rdflib.URIRef(ns.bse.filename), rdflib.Literal('foo_second', datatype=rdflib.XSD.string)), + (rdflib.URIRef(pre_file + 'b8fd7fba818254166a6043195004138ebda6923e012442f819a2c49671136c70'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Entity)), + (rdflib.URIRef(pre_file + 'b8fd7fba818254166a6043195004138ebda6923e012442f819a2c49671136c70'), rdflib.URIRef(ns.bse.author), rdflib.Literal('Me, myself, and I', datatype=rdflib.XSD.string)), + (rdflib.URIRef(pre_file + 'b8fd7fba818254166a6043195004138ebda6923e012442f819a2c49671136c70'), rdflib.URIRef(ns.bse.filename), rdflib.Literal('bar_second', datatype=rdflib.XSD.string)), + (rdflib.URIRef(pre_file + 'd43758ace82154a1cc10ca0dfef63cb20dd831f9c87edd6dc06539eefe67371d'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Entity)), + (rdflib.URIRef(pre_file + 'd43758ace82154a1cc10ca0dfef63cb20dd831f9c87edd6dc06539eefe67371d'), rdflib.URIRef(ns.bse.author), rdflib.Literal('Me, myself, and I', datatype=rdflib.XSD.string)), + (rdflib.URIRef(pre_file + 'd43758ace82154a1cc10ca0dfef63cb20dd831f9c87edd6dc06539eefe67371d'), rdflib.URIRef(ns.bse.filename), rdflib.Literal('foo_first', datatype=rdflib.XSD.string)), + (rdflib.URIRef(pre_file + 'd803187cbf3676ae9d38126270a6152c60431589aa3bb3824baf8954e9c097f1'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Entity)), + (rdflib.URIRef(pre_file + 'd803187cbf3676ae9d38126270a6152c60431589aa3bb3824baf8954e9c097f1'), rdflib.URIRef(ns.bse.author), rdflib.Literal('Me, myself, and I', datatype=rdflib.XSD.string)), + (rdflib.URIRef(pre_file + 'd803187cbf3676ae9d38126270a6152c60431589aa3bb3824baf8954e9c097f1'), rdflib.URIRef(ns.bse.filename), rdflib.Literal('td_second', datatype=rdflib.XSD.string)), + (rdflib.URIRef(pre_file + 'accb115d266ad60c53cd01a7f7130f245886ce8eaf69bc85319febc11d9fe089'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Entity)), + (rdflib.URIRef(pre_file + 'accb115d266ad60c53cd01a7f7130f245886ce8eaf69bc85319febc11d9fe089'), rdflib.URIRef(ns.bse.author), rdflib.Literal('Me, myself, and I', datatype=rdflib.XSD.string)), + (rdflib.URIRef(pre_file + 'accb115d266ad60c53cd01a7f7130f245886ce8eaf69bc85319febc11d9fe089'), rdflib.URIRef(ns.bse.filename), rdflib.Literal('testimage.jpg', datatype=rdflib.XSD.string)), + # features + (rdflib.URIRef(pre_file + 'accb115d266ad60c53cd01a7f7130f245886ce8eaf69bc85319febc11d9fe089'), rdflib.URIRef('https://schema.bsfs.io/ie/Node/Entity#colors_spatial_0658f2234a054e1dd59a14462c89f7733e019160419c796356aa831498bd0a04'), + rdflib.Literal( + '(91, 127, 121, 94, 138, 167, 163, 134, 190, 138, 170, 156, 121, 142, 159)', + datatype=rdflib.URIRef('https://schema.bsfs.io/ie/Literal/Array/Feature/ColorsSpatial#0658f2234a054e1dd59a14462c89f7733e019160419c796356aa831498bd0a04'))), + # links to previews + (rdflib.URIRef(pre_file + '2f4109b40107cc50e0884755a1a961ed126887e49b8dbaf0e146b2e226aa6647'), rdflib.URIRef(ns.bse.preview), rdflib.URIRef(pre_preview + '79cb8a7e6369361a4f4cb7ff729c1ed3fcf87204769623d6fbd6ebfae601e5c7_s50')), + (rdflib.URIRef(pre_file + '441f3d10c8ff489fe8e33e639606512f6c463151cc429de7e554b9af670c2ece'), rdflib.URIRef(ns.bse.preview), rdflib.URIRef(pre_preview + 'a8b3245636074d5370283b690281abda8ffdff12ce8b1af77c8bc0a4c85be860_s50')), + (rdflib.URIRef(pre_file + '69b98ecf7aff3e95b09688ba93331678eb8397817111f674c9558e6dd8f5e871'), rdflib.URIRef(ns.bse.preview), rdflib.URIRef(pre_preview + '968b9aa178585bc8d1fca0e4e32b8cf30b3941eff72f34e320584aaae8fd23ac_s50')), + (rdflib.URIRef(pre_file + '78f7eb7f0d8221cdb2cb26c978fa42a11f75eb87becc768f4474134cb1e06926'), rdflib.URIRef(ns.bse.preview), rdflib.URIRef(pre_preview + 'dbfd8ebc0557c4925e9ff8411629a74a15eca934a4c2a6bd3134dd81d2f95a36_s50')), + (rdflib.URIRef(pre_file + '80818b8ec2ee1919116dba9c8a7e0a4608313cf3b463cd88e9ed77a700dd92d3'), rdflib.URIRef(ns.bse.preview), rdflib.URIRef(pre_preview + '567049149769e1d02e6af6cfee3991f7cf0cbc935cbf6a566047f40155fb13a8_s50')), + (rdflib.URIRef(pre_file + '976d2ea0e58488678cc7e435fbfadabfb6eb6cf50ad51862f38f73729ed11795'), rdflib.URIRef(ns.bse.preview), rdflib.URIRef(pre_preview + 'df2185d8927ccef65c92fc90b94e800b02791354d8dede9dd9aa0e2c2cb1e91e_s50')), + (rdflib.URIRef(pre_file + '997e2fbb7494a3818ec782d2bc87bf1cffafba6b9c0f658e4a6c18a723e944d3'), rdflib.URIRef(ns.bse.preview), rdflib.URIRef(pre_preview + '9827509a74a60dfceed11936f7f624e9c932f66c8c0d20d355d56f8c3c9b56b1_s50')), + (rdflib.URIRef(pre_file + 'a8af899ecdab60dfaea8ec7f934053624c80a1054539e163f2c7eaa986c2777d'), rdflib.URIRef(ns.bse.preview), rdflib.URIRef(pre_preview + '7a975385a110c21fcd12e238fab9501550fa02f6328749068a3bffd65e291027_s50')), + (rdflib.URIRef(pre_file + 'accb115d266ad60c53cd01a7f7130f245886ce8eaf69bc85319febc11d9fe089'), rdflib.URIRef(ns.bse.preview), rdflib.URIRef(pre_preview + '2656e303d7218300326df73b64f312d8b37eb980358be27a38b5f63dae259be3_s50')), + (rdflib.URIRef(pre_file + 'b8fd7fba818254166a6043195004138ebda6923e012442f819a2c49671136c70'), rdflib.URIRef(ns.bse.preview), rdflib.URIRef(pre_preview + 'a63c84e647138a2b68113474212f6aee542b3707171ff178551db3c296e59817_s50')), + (rdflib.URIRef(pre_file + 'd43758ace82154a1cc10ca0dfef63cb20dd831f9c87edd6dc06539eefe67371d'), rdflib.URIRef(ns.bse.preview), rdflib.URIRef(pre_preview + '26f16643b2570ac5b2d1f8c373d492cb724aae2dd8d71a0b63647838ed651254_s50')), + (rdflib.URIRef(pre_file + 'd803187cbf3676ae9d38126270a6152c60431589aa3bb3824baf8954e9c097f1'), rdflib.URIRef(ns.bse.preview), rdflib.URIRef(pre_preview + '5d1235838c3d501204bb09c2de563d7e4a7fd17b7ec4ff302221c0e88c4741aa_s50')), + # preview dimensions + (rdflib.URIRef(pre_preview + '2656e303d7218300326df73b64f312d8b37eb980358be27a38b5f63dae259be3_s50'), rdflib.URIRef(ns.bsp.height), rdflib.Literal('33', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))), + (rdflib.URIRef(pre_preview + '2656e303d7218300326df73b64f312d8b37eb980358be27a38b5f63dae259be3_s50'), rdflib.URIRef(ns.bsp.width), rdflib.Literal('50', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))), + (rdflib.URIRef(pre_preview + '2656e303d7218300326df73b64f312d8b37eb980358be27a38b5f63dae259be3_s50'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Preview)), + (rdflib.URIRef(pre_preview + '26f16643b2570ac5b2d1f8c373d492cb724aae2dd8d71a0b63647838ed651254_s50'), rdflib.URIRef(ns.bsp.height), rdflib.Literal('50', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))), + (rdflib.URIRef(pre_preview + '26f16643b2570ac5b2d1f8c373d492cb724aae2dd8d71a0b63647838ed651254_s50'), rdflib.URIRef(ns.bsp.width), rdflib.Literal('36', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))), + (rdflib.URIRef(pre_preview + '26f16643b2570ac5b2d1f8c373d492cb724aae2dd8d71a0b63647838ed651254_s50'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Preview)), + (rdflib.URIRef(pre_preview + '567049149769e1d02e6af6cfee3991f7cf0cbc935cbf6a566047f40155fb13a8_s50'), rdflib.URIRef(ns.bsp.height), rdflib.Literal('50', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))), + (rdflib.URIRef(pre_preview + '567049149769e1d02e6af6cfee3991f7cf0cbc935cbf6a566047f40155fb13a8_s50'), rdflib.URIRef(ns.bsp.width), rdflib.Literal('36', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))), + (rdflib.URIRef(pre_preview + '567049149769e1d02e6af6cfee3991f7cf0cbc935cbf6a566047f40155fb13a8_s50'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Preview)), + (rdflib.URIRef(pre_preview + '5d1235838c3d501204bb09c2de563d7e4a7fd17b7ec4ff302221c0e88c4741aa_s50'), rdflib.URIRef(ns.bsp.height), rdflib.Literal('50', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))), + (rdflib.URIRef(pre_preview + '5d1235838c3d501204bb09c2de563d7e4a7fd17b7ec4ff302221c0e88c4741aa_s50'), rdflib.URIRef(ns.bsp.width), rdflib.Literal('36', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))), + (rdflib.URIRef(pre_preview + '5d1235838c3d501204bb09c2de563d7e4a7fd17b7ec4ff302221c0e88c4741aa_s50'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Preview)), + (rdflib.URIRef(pre_preview + '79cb8a7e6369361a4f4cb7ff729c1ed3fcf87204769623d6fbd6ebfae601e5c7_s50'), rdflib.URIRef(ns.bsp.height), rdflib.Literal('50', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))), + (rdflib.URIRef(pre_preview + '79cb8a7e6369361a4f4cb7ff729c1ed3fcf87204769623d6fbd6ebfae601e5c7_s50'), rdflib.URIRef(ns.bsp.width), rdflib.Literal('36', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))), + (rdflib.URIRef(pre_preview + '79cb8a7e6369361a4f4cb7ff729c1ed3fcf87204769623d6fbd6ebfae601e5c7_s50'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Preview)), + (rdflib.URIRef(pre_preview + '7a975385a110c21fcd12e238fab9501550fa02f6328749068a3bffd65e291027_s50'), rdflib.URIRef(ns.bsp.height), rdflib.Literal('50', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))), + (rdflib.URIRef(pre_preview + '7a975385a110c21fcd12e238fab9501550fa02f6328749068a3bffd65e291027_s50'), rdflib.URIRef(ns.bsp.width), rdflib.Literal('36', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))), + (rdflib.URIRef(pre_preview + '7a975385a110c21fcd12e238fab9501550fa02f6328749068a3bffd65e291027_s50'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Preview)), + (rdflib.URIRef(pre_preview + '968b9aa178585bc8d1fca0e4e32b8cf30b3941eff72f34e320584aaae8fd23ac_s50'), rdflib.URIRef(ns.bsp.height), rdflib.Literal('50', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))), + (rdflib.URIRef(pre_preview + '968b9aa178585bc8d1fca0e4e32b8cf30b3941eff72f34e320584aaae8fd23ac_s50'), rdflib.URIRef(ns.bsp.width), rdflib.Literal('36', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))), + (rdflib.URIRef(pre_preview + '968b9aa178585bc8d1fca0e4e32b8cf30b3941eff72f34e320584aaae8fd23ac_s50'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Preview)), + (rdflib.URIRef(pre_preview + '9827509a74a60dfceed11936f7f624e9c932f66c8c0d20d355d56f8c3c9b56b1_s50'), rdflib.URIRef(ns.bsp.height), rdflib.Literal('50', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))), + (rdflib.URIRef(pre_preview + '9827509a74a60dfceed11936f7f624e9c932f66c8c0d20d355d56f8c3c9b56b1_s50'), rdflib.URIRef(ns.bsp.width), rdflib.Literal('36', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))), + (rdflib.URIRef(pre_preview + '9827509a74a60dfceed11936f7f624e9c932f66c8c0d20d355d56f8c3c9b56b1_s50'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Preview)), + (rdflib.URIRef(pre_preview + 'a63c84e647138a2b68113474212f6aee542b3707171ff178551db3c296e59817_s50'), rdflib.URIRef(ns.bsp.height), rdflib.Literal('50', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))), + (rdflib.URIRef(pre_preview + 'a63c84e647138a2b68113474212f6aee542b3707171ff178551db3c296e59817_s50'), rdflib.URIRef(ns.bsp.width), rdflib.Literal('36', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))), + (rdflib.URIRef(pre_preview + 'a63c84e647138a2b68113474212f6aee542b3707171ff178551db3c296e59817_s50'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Preview)), + (rdflib.URIRef(pre_preview + 'a8b3245636074d5370283b690281abda8ffdff12ce8b1af77c8bc0a4c85be860_s50'), rdflib.URIRef(ns.bsp.height), rdflib.Literal('50', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))), + (rdflib.URIRef(pre_preview + 'a8b3245636074d5370283b690281abda8ffdff12ce8b1af77c8bc0a4c85be860_s50'), rdflib.URIRef(ns.bsp.width), rdflib.Literal('36', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))), + (rdflib.URIRef(pre_preview + 'a8b3245636074d5370283b690281abda8ffdff12ce8b1af77c8bc0a4c85be860_s50'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Preview)), + (rdflib.URIRef(pre_preview + 'dbfd8ebc0557c4925e9ff8411629a74a15eca934a4c2a6bd3134dd81d2f95a36_s50'), rdflib.URIRef(ns.bsp.height), rdflib.Literal('50', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))), + (rdflib.URIRef(pre_preview + 'dbfd8ebc0557c4925e9ff8411629a74a15eca934a4c2a6bd3134dd81d2f95a36_s50'), rdflib.URIRef(ns.bsp.width), rdflib.Literal('36', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))), + (rdflib.URIRef(pre_preview + 'dbfd8ebc0557c4925e9ff8411629a74a15eca934a4c2a6bd3134dd81d2f95a36_s50'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Preview)), + (rdflib.URIRef(pre_preview + 'df2185d8927ccef65c92fc90b94e800b02791354d8dede9dd9aa0e2c2cb1e91e_s50'), rdflib.URIRef(ns.bsp.height), rdflib.Literal('50', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))), + (rdflib.URIRef(pre_preview + 'df2185d8927ccef65c92fc90b94e800b02791354d8dede9dd9aa0e2c2cb1e91e_s50'), rdflib.URIRef(ns.bsp.width), rdflib.Literal('36', datatype=rdflib.URIRef('http://www.w3.org/2001/XMLSchema#integer'))), + (rdflib.URIRef(pre_preview + 'df2185d8927ccef65c92fc90b94e800b02791354d8dede9dd9aa0e2c2cb1e91e_s50'), rdflib.RDF.type, rdflib.URIRef(ns.bsn.Preview)), + # assets + (rdflib.URIRef(pre_preview + '2656e303d7218300326df73b64f312d8b37eb980358be27a38b5f63dae259be3_s50'), rdflib.URIRef(ns.bsp.asset), rdflib.Literal('/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAAhADIDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDi9Ktb+O3khZTg/wAB7VSGnKkkhkAR85weteo3Vl9mvLtWjVWEJaN/9rsD7HkVwNza3kmsn7RYsDuzsdSVb/GvLo15W9rKNkVDmvzKN0dx4L1Sb+x2S7jZ7aM7BKF+XPoffkVdOpWDSSI9sGizk5HWuE8S69q0NnHptnB9ms7Nh8lr+6SSXALhsHJUcY7kitPTLi51nR0nMKpO6ZkCHABxngdq1xGKnSs1Kyvrc7qEMW2/Zrz/AKudnbXXhuaEiO3jjY9TtxVG8ht3mQwgOnaubuVmtbFV2gSjjn1q1prajJF+9dEQdMVjPHKtFxaXqc9fE1JXpzjr+J0Is7fA+VaKwmludx/0xevrRXLaH8xyfVZdjpNFsgsUlpryPkjyVuVJ6AnH8z/I1flS30m2ezvdt3bbd1teRL8yntu/xGfeua1zXtbs7dh5I8mRdhkD7mYEY5GOf51Jp+vW8Vnu1KT7FJKMmO5b5JcdwDxn1HFfR1KUZRd1v93zPoaFfD1J+5Kz+79DjfEV9Dc3E0hk5Zi5ZR1btx+NYNlrn9nllhkKgnPpnjr9Of1H0rrdc0bQtTvgsWbSRiwJjk2K+ADwrZ9RyOOa4/U/AWs21y0mmhL60dyI5IpVLduGGeCM/jXmPL201N3NK9SpfngrryOr0y+i1fT4lvZ9gR9pYfM5I9v8/wBK2/7FneFmCXEMLcIbhwpb3A6gVwGiaR4o03UYhbaZOZ88RqA27HXoeB9K9PgiYRRyal4Y1KKVhlyHbr3966MPgIRpuMtNROjTr+/JWn+P4mB/wix/5/o/+/lFdoLXT8DPhfUfx8yiuj6lT7v8P8hex85ffEZef8gu0+oriPiZ/rNI+j/zFFFbYn+Ez5uh8ZP4l/5Cq/8AYN/9nFU/CH/Hvd/9dv8A2Wiih/Ee7k/wv1/Q63Qv9fb/APXT+ldFrP8Ax/xfRP8A0IUUVX2T0K38RD5v9dJ/vH+dFFFUC2P/2Q==', datatype=rdflib.URIRef(ns.bsl.BinaryBlob))), + (rdflib.URIRef(pre_preview + '26f16643b2570ac5b2d1f8c373d492cb724aae2dd8d71a0b63647838ed651254_s50'), rdflib.URIRef(ns.bsp.asset), rdflib.Literal('/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCAAyACQBAREA/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APdLq6eAgKoI25Oc+oHYe9Qfb5sr+6UZHUhuv5VYjnZyQSo9gpNTgP3YH6Lj+tPqCa2jmILrkgEVH/Z8HHy8DjGB/hUq26IMAkj0IH+FTUUUUUUUUUUUUUUUUUUUUUUUUUUV/9k=', datatype=rdflib.URIRef(ns.bsl.BinaryBlob))), + (rdflib.URIRef(pre_preview + '5d1235838c3d501204bb09c2de563d7e4a7fd17b7ec4ff302221c0e88c4741aa_s50'), rdflib.URIRef(ns.bsp.asset), rdflib.Literal('/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCAAyACQBAREA/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APdLm5eBwFVTkd89c+1Qf2hMSAI15/3v8KtR3DSFgIiceh7/AMv1qcHIzjFLVO7tnncFduAMc+v5GoDZXJAw65A/vdT/AN81PDasjMXPBGAMgj8toqxHGIxgfyA/lUlFFFFFFFFFFFFFFFFFFFFFFFFFf//Z', datatype=rdflib.URIRef(ns.bsl.BinaryBlob))), + (rdflib.URIRef(pre_preview + '79cb8a7e6369361a4f4cb7ff729c1ed3fcf87204769623d6fbd6ebfae601e5c7_s50'), rdflib.URIRef(ns.bsp.asset), rdflib.Literal('/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCAAyACQBAREA/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APdLq5eFgEQEYySQf6CoDqEo2/u1yevDf4VJHfZ3eZhNvojHvj0q4h3IDnOR1AxmnVXntEuDlyR8u3gA8fiDUR02I4G9uOei9eeenvTvsS5J82Tn6cfpUsMPkrgSOw9Gxx+lTUUUUUUUUUUUUUUUUUUUUUUUUUV//9k=', datatype=rdflib.URIRef(ns.bsl.BinaryBlob))), + (rdflib.URIRef(pre_preview + '7a975385a110c21fcd12e238fab9501550fa02f6328749068a3bffd65e291027_s50'), rdflib.URIRef(ns.bsp.asset), rdflib.Literal('/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCAAyACQBAREA/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APdLq6eBgFUHjPIJ7+wqudQmGMxpyMk4bA6+30/OrSyzFvm8kDrjecgflVhSGGVIIPcUtV57RLjBZmBAxwB/UGov7NiGMMw25wQF45z6VKtrGuc7mz6n3zVjpRRRRRRRRRRRRRRRRRRRRRRRRRRX/9k=', datatype=rdflib.URIRef(ns.bsl.BinaryBlob))), + (rdflib.URIRef(pre_preview + '968b9aa178585bc8d1fca0e4e32b8cf30b3941eff72f34e320584aaae8fd23ac_s50'), rdflib.URIRef(ns.bsp.asset), rdflib.Literal('/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCAAyACQBAREA/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APdLm5eFsIgPy55zyc47CoRfTkf6uPOOckjnn29qmS5dmbK52noq5OPzqwj7/wCFl/3hin1n36MzgqhbCkcKTz+ANUzA5Cjynx7IRjn/AHfT271d8gAEFGxzwCfX2WrMR2gIQfbg/wCAqaiiiiiiiiiiiiiiiiiiiiiiiiiv/9k=', datatype=rdflib.URIRef(ns.bsl.BinaryBlob))), + (rdflib.URIRef(pre_preview + '9827509a74a60dfceed11936f7f624e9c932f66c8c0d20d355d56f8c3c9b56b1_s50'), rdflib.URIRef(ns.bsp.asset), rdflib.Literal('/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCAAyACQBAREA/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APdLq5eAgKoPyknIPb6ColvZywHlp79R+WRU3nT7iojHXqQR6VYUk9QR9adVK8t3mdSqggLjJxkHPuD/AJFVlsZ/l+RFIXGTtI6k9Npq3FbFdwYKAemAp/8AZR/WrKLtGMn9KdRRRRRRRRRRRRRRRRRRRRRRRRRX/9k=', datatype=rdflib.URIRef(ns.bsl.BinaryBlob))), + (rdflib.URIRef(pre_preview + '567049149769e1d02e6af6cfee3991f7cf0cbc935cbf6a566047f40155fb13a8_s50'), rdflib.URIRef(ns.bsp.asset), rdflib.Literal('/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCAAyACQBAREA/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APdLm5eFwFVSCpPIPYj0HvVf+0ZiFxGnIychhj9KtQyTSNkiLZ7E5B/EVZorN1EZkXAJIQ4wM9x7GqYAAXCAgDHKnGMn0X/Oa0LeMJudcKx64iJz+OATVoOOh3E+oUipKayK33lB+opPKj/55r+VHlR8/Iv5U+iiiiiiiiiiiiiiiiiiiiiv/9k=', datatype=rdflib.URIRef(ns.bsl.BinaryBlob))), + (rdflib.URIRef(pre_preview + 'df2185d8927ccef65c92fc90b94e800b02791354d8dede9dd9aa0e2c2cb1e91e_s50'), rdflib.URIRef(ns.bsp.asset), rdflib.Literal('/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCAAyACQBAREA/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APdLm5eGQBVU5XPIJ7j0FQfb5sgiNcH2b39vapkvGPDIucjoTjBOPSrKuHHGencEU+ql1am4IIYA7cDIB757g1CunFWByAAOCMAg5yD07VcCEN0P/fZNS0UUUUUUUUUUUUUUUUUUUUUUUUUV/9k=', datatype=rdflib.URIRef(ns.bsl.BinaryBlob))), + (rdflib.URIRef(pre_preview + 'a63c84e647138a2b68113474212f6aee542b3707171ff178551db3c296e59817_s50'), rdflib.URIRef(ns.bsp.asset), rdflib.Literal('/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCAAyACQBAREA/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APdLq6eBgFUH5c5IPqPQVANQmJUeWvPXhvUj09qspcM2cAnHHCE/rmpUl3nGx1+oxUlVLq1M7KQQPlI5APXHqDUKacyMDvHTsBk9fb3q4kXl5IYkk5OQB/ICpaKKKKKKKKKKKKKKKKKKKKKKKKKK/9k=', datatype=rdflib.URIRef(ns.bsl.BinaryBlob))), + (rdflib.URIRef(pre_preview + 'a8b3245636074d5370283b690281abda8ffdff12ce8b1af77c8bc0a4c85be860_s50'), rdflib.URIRef(ns.bsp.asset), rdflib.Literal('/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCAAyACQBAREA/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APdbm4eF1CqDkZOQT3HoKr/b5vl/dpkj/awDnHp06fzqZLiRmIPk47fMQf1FXKKikgilOZEDHGOaZ9itsg+SuQMA08QoowNwHoGP+NO8serf99Gn0UUUUUUUUUUUUUUUUUUUUUUUUV//2Q==', datatype=rdflib.URIRef(ns.bsl.BinaryBlob))), + (rdflib.URIRef(pre_preview + 'dbfd8ebc0557c4925e9ff8411629a74a15eca934a4c2a6bd3134dd81d2f95a36_s50'), rdflib.URIRef(ns.bsp.asset), rdflib.Literal('/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCAAyACQBAREA/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APdbm5eFwqqDkZ5B9QOw96rHUZgoPlLkgno3b8Kel7IzspVePYgdcck1YilaTA3JnqQFPT86sVQvoXkYFUDEKRz7np0NVWtZcAiLkd8Dg/8AfPqO3rWhEk6thsbc9mz+mP61Zoooooooooooooooooooooooooor/9k=', datatype=rdflib.URIRef(ns.bsl.BinaryBlob))), })) # NOTE: we don't check ns.bsm.t_created since it depends on the execution time. Triples would look like this: - # (rdflib.URIRef(prefix + '2f4109b40107cc50e0884755a1a961ed126887e49b8dbaf0e146b2e226aa6647'), rdflib.URIRef(ns.bsm.t_created), rdflib.Literal('1670..........', datatype=rdflib.XSD.integer)), - # (rdflib.URIRef(prefix + '441f3d10c8ff489fe8e33e639606512f6c463151cc429de7e554b9af670c2ece'), rdflib.URIRef(ns.bsm.t_created), rdflib.Literal('1670..........', datatype=rdflib.XSD.integer)), - # (rdflib.URIRef(prefix + '69b98ecf7aff3e95b09688ba93331678eb8397817111f674c9558e6dd8f5e871'), rdflib.URIRef(ns.bsm.t_created), rdflib.Literal('1670..........', datatype=rdflib.XSD.integer)), - # (rdflib.URIRef(prefix + '78f7eb7f0d8221cdb2cb26c978fa42a11f75eb87becc768f4474134cb1e06926'), rdflib.URIRef(ns.bsm.t_created), rdflib.Literal('1670..........', datatype=rdflib.XSD.integer)), - # (rdflib.URIRef(prefix + '80818b8ec2ee1919116dba9c8a7e0a4608313cf3b463cd88e9ed77a700dd92d3'), rdflib.URIRef(ns.bsm.t_created), rdflib.Literal('1670..........', datatype=rdflib.XSD.integer)), - # (rdflib.URIRef(prefix + '976d2ea0e58488678cc7e435fbfadabfb6eb6cf50ad51862f38f73729ed11795'), rdflib.URIRef(ns.bsm.t_created), rdflib.Literal('1670..........', datatype=rdflib.XSD.integer)), - # (rdflib.URIRef(prefix + '997e2fbb7494a3818ec782d2bc87bf1cffafba6b9c0f658e4a6c18a723e944d3'), rdflib.URIRef(ns.bsm.t_created), rdflib.Literal('1670..........', datatype=rdflib.XSD.integer)), - # (rdflib.URIRef(prefix + 'a8af899ecdab60dfaea8ec7f934053624c80a1054539e163f2c7eaa986c2777d'), rdflib.URIRef(ns.bsm.t_created), rdflib.Literal('1670..........', datatype=rdflib.XSD.integer)), - # (rdflib.URIRef(prefix + 'b8fd7fba818254166a6043195004138ebda6923e012442f819a2c49671136c70'), rdflib.URIRef(ns.bsm.t_created), rdflib.Literal('1670..........', datatype=rdflib.XSD.integer)), - # (rdflib.URIRef(prefix + 'd43758ace82154a1cc10ca0dfef63cb20dd831f9c87edd6dc06539eefe67371d'), rdflib.URIRef(ns.bsm.t_created), rdflib.Literal('1670..........', datatype=rdflib.XSD.integer)), - # (rdflib.URIRef(prefix + 'd803187cbf3676ae9d38126270a6152c60431589aa3bb3824baf8954e9c097f1'), rdflib.URIRef(ns.bsm.t_created), rdflib.Literal('1670..........', datatype=rdflib.XSD.integer)), + # (rdflib.URIRef(pre_file + '2f4109b40107cc50e0884755a1a961ed126887e49b8dbaf0e146b2e226aa6647'), rdflib.URIRef(ns.bsm.t_created), rdflib.Literal('1670..........', datatype=rdflib.XSD.integer)), + # (rdflib.URIRef(pre_file + '441f3d10c8ff489fe8e33e639606512f6c463151cc429de7e554b9af670c2ece'), rdflib.URIRef(ns.bsm.t_created), rdflib.Literal('1670..........', datatype=rdflib.XSD.integer)), + # (rdflib.URIRef(pre_file + '80818b8ec2ee1919116dba9c8a7e0a4608313cf3b463cd88e9ed77a700dd92d3'), rdflib.URIRef(ns.bsm.t_created), rdflib.Literal('1670..........', datatype=rdflib.XSD.integer)), + # ... # instead, we simply check if there's such a predicate for each file - self.assertSetEqual({sub for sub, _ in bsfs._backend._graph.subject_objects(rdflib.URIRef(ns.bsm.t_created))}, { - rdflib.URIRef(prefix + '2f4109b40107cc50e0884755a1a961ed126887e49b8dbaf0e146b2e226aa6647'), - rdflib.URIRef(prefix + '441f3d10c8ff489fe8e33e639606512f6c463151cc429de7e554b9af670c2ece'), - rdflib.URIRef(prefix + '69b98ecf7aff3e95b09688ba93331678eb8397817111f674c9558e6dd8f5e871'), - rdflib.URIRef(prefix + '78f7eb7f0d8221cdb2cb26c978fa42a11f75eb87becc768f4474134cb1e06926'), - rdflib.URIRef(prefix + '80818b8ec2ee1919116dba9c8a7e0a4608313cf3b463cd88e9ed77a700dd92d3'), - rdflib.URIRef(prefix + '976d2ea0e58488678cc7e435fbfadabfb6eb6cf50ad51862f38f73729ed11795'), - rdflib.URIRef(prefix + '997e2fbb7494a3818ec782d2bc87bf1cffafba6b9c0f658e4a6c18a723e944d3'), - rdflib.URIRef(prefix + 'a8af899ecdab60dfaea8ec7f934053624c80a1054539e163f2c7eaa986c2777d'), - rdflib.URIRef(prefix + 'b8fd7fba818254166a6043195004138ebda6923e012442f819a2c49671136c70'), - rdflib.URIRef(prefix + 'd43758ace82154a1cc10ca0dfef63cb20dd831f9c87edd6dc06539eefe67371d'), - rdflib.URIRef(prefix + 'd803187cbf3676ae9d38126270a6152c60431589aa3bb3824baf8954e9c097f1'), + self.assertSetEqual({sub for sub, _ in bsfs._backend._graph.subject_objects(rdflib.URIRef(ns.bsfs.Node().t_created))}, { + rdflib.URIRef(pre_file + '2f4109b40107cc50e0884755a1a961ed126887e49b8dbaf0e146b2e226aa6647'), + rdflib.URIRef(pre_file + '441f3d10c8ff489fe8e33e639606512f6c463151cc429de7e554b9af670c2ece'), + rdflib.URIRef(pre_file + '69b98ecf7aff3e95b09688ba93331678eb8397817111f674c9558e6dd8f5e871'), + rdflib.URIRef(pre_file + '78f7eb7f0d8221cdb2cb26c978fa42a11f75eb87becc768f4474134cb1e06926'), + rdflib.URIRef(pre_file + '80818b8ec2ee1919116dba9c8a7e0a4608313cf3b463cd88e9ed77a700dd92d3'), + rdflib.URIRef(pre_file + '976d2ea0e58488678cc7e435fbfadabfb6eb6cf50ad51862f38f73729ed11795'), + rdflib.URIRef(pre_file + '997e2fbb7494a3818ec782d2bc87bf1cffafba6b9c0f658e4a6c18a723e944d3'), + rdflib.URIRef(pre_file + 'a8af899ecdab60dfaea8ec7f934053624c80a1054539e163f2c7eaa986c2777d'), + rdflib.URIRef(pre_file + 'b8fd7fba818254166a6043195004138ebda6923e012442f819a2c49671136c70'), + rdflib.URIRef(pre_file + 'd43758ace82154a1cc10ca0dfef63cb20dd831f9c87edd6dc06539eefe67371d'), + rdflib.URIRef(pre_file + 'd803187cbf3676ae9d38126270a6152c60431589aa3bb3824baf8954e9c097f1'), + rdflib.URIRef(pre_file + 'accb115d266ad60c53cd01a7f7130f245886ce8eaf69bc85319febc11d9fe089'), + rdflib.URIRef(pre_preview + '26f16643b2570ac5b2d1f8c373d492cb724aae2dd8d71a0b63647838ed651254_s50'), + rdflib.URIRef(pre_preview + 'a63c84e647138a2b68113474212f6aee542b3707171ff178551db3c296e59817_s50'), + rdflib.URIRef(pre_preview + '9827509a74a60dfceed11936f7f624e9c932f66c8c0d20d355d56f8c3c9b56b1_s50'), + rdflib.URIRef(pre_preview + '2656e303d7218300326df73b64f312d8b37eb980358be27a38b5f63dae259be3_s50'), + rdflib.URIRef(pre_preview + '79cb8a7e6369361a4f4cb7ff729c1ed3fcf87204769623d6fbd6ebfae601e5c7_s50'), + rdflib.URIRef(pre_preview + 'dbfd8ebc0557c4925e9ff8411629a74a15eca934a4c2a6bd3134dd81d2f95a36_s50'), + rdflib.URIRef(pre_preview + '5d1235838c3d501204bb09c2de563d7e4a7fd17b7ec4ff302221c0e88c4741aa_s50'), + rdflib.URIRef(pre_preview + '567049149769e1d02e6af6cfee3991f7cf0cbc935cbf6a566047f40155fb13a8_s50'), + rdflib.URIRef(pre_preview + 'df2185d8927ccef65c92fc90b94e800b02791354d8dede9dd9aa0e2c2cb1e91e_s50'), + rdflib.URIRef(pre_preview + 'a8b3245636074d5370283b690281abda8ffdff12ce8b1af77c8bc0a4c85be860_s50'), + rdflib.URIRef(pre_preview + '7a975385a110c21fcd12e238fab9501550fa02f6328749068a3bffd65e291027_s50'), + rdflib.URIRef(pre_preview + '968b9aa178585bc8d1fca0e4e32b8cf30b3941eff72f34e320584aaae8fd23ac_s50'), }) def test_print(self): outbuf = io.StringIO() with contextlib.redirect_stdout(outbuf): bsfs = main([ + '--config', + self.config_path, '--print', '-r', - '--user', 'http://example.com/me', + '--host', 'http://example.com', + '--user', 'me', os.path.join(os.path.dirname(__file__), 'testdir'), os.path.join(os.path.dirname(__file__), 'testfile'), ]) - self.assertSetEqual(set(outbuf.getvalue().split('\n')) - {''}, { - f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#2f4109b40107cc50e0884755a1a961ed126887e49b8dbaf0e146b2e226aa6647) Predicate({ns.bse.author}) Me, myself, and I', - f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#2f4109b40107cc50e0884755a1a961ed126887e49b8dbaf0e146b2e226aa6647) Predicate({ns.bse.filename}) alpha_second', - f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#2f4109b40107cc50e0884755a1a961ed126887e49b8dbaf0e146b2e226aa6647) Predicate({ns.bse.filesize}) 696', - f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#441f3d10c8ff489fe8e33e639606512f6c463151cc429de7e554b9af670c2ece) Predicate({ns.bse.author}) Me, myself, and I', - f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#441f3d10c8ff489fe8e33e639606512f6c463151cc429de7e554b9af670c2ece) Predicate({ns.bse.filename}) omega_second', - f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#441f3d10c8ff489fe8e33e639606512f6c463151cc429de7e554b9af670c2ece) Predicate({ns.bse.filesize}) 503', - f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#69b98ecf7aff3e95b09688ba93331678eb8397817111f674c9558e6dd8f5e871) Predicate({ns.bse.author}) Me, myself, and I', - f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#69b98ecf7aff3e95b09688ba93331678eb8397817111f674c9558e6dd8f5e871) Predicate({ns.bse.filename}) td_first', - f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#69b98ecf7aff3e95b09688ba93331678eb8397817111f674c9558e6dd8f5e871) Predicate({ns.bse.filesize}) 911', - f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#78f7eb7f0d8221cdb2cb26c978fa42a11f75eb87becc768f4474134cb1e06926) Predicate({ns.bse.author}) Me, myself, and I', - f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#78f7eb7f0d8221cdb2cb26c978fa42a11f75eb87becc768f4474134cb1e06926) Predicate({ns.bse.filename}) testfile', - f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#78f7eb7f0d8221cdb2cb26c978fa42a11f75eb87becc768f4474134cb1e06926) Predicate({ns.bse.filesize}) 885', - f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#80818b8ec2ee1919116dba9c8a7e0a4608313cf3b463cd88e9ed77a700dd92d3) Predicate({ns.bse.author}) Me, myself, and I', - f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#80818b8ec2ee1919116dba9c8a7e0a4608313cf3b463cd88e9ed77a700dd92d3) Predicate({ns.bse.filename}) bar_first', - f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#80818b8ec2ee1919116dba9c8a7e0a4608313cf3b463cd88e9ed77a700dd92d3) Predicate({ns.bse.filesize}) 956', - f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#976d2ea0e58488678cc7e435fbfadabfb6eb6cf50ad51862f38f73729ed11795) Predicate({ns.bse.author}) Me, myself, and I', - f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#976d2ea0e58488678cc7e435fbfadabfb6eb6cf50ad51862f38f73729ed11795) Predicate({ns.bse.filename}) omega_first', - f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#976d2ea0e58488678cc7e435fbfadabfb6eb6cf50ad51862f38f73729ed11795) Predicate({ns.bse.filesize}) 648', - f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#997e2fbb7494a3818ec782d2bc87bf1cffafba6b9c0f658e4a6c18a723e944d3) Predicate({ns.bse.author}) Me, myself, and I', - f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#997e2fbb7494a3818ec782d2bc87bf1cffafba6b9c0f658e4a6c18a723e944d3) Predicate({ns.bse.filename}) alpha_first', - f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#997e2fbb7494a3818ec782d2bc87bf1cffafba6b9c0f658e4a6c18a723e944d3) Predicate({ns.bse.filesize}) 754', - f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#a8af899ecdab60dfaea8ec7f934053624c80a1054539e163f2c7eaa986c2777d) Predicate({ns.bse.author}) Me, myself, and I', - f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#a8af899ecdab60dfaea8ec7f934053624c80a1054539e163f2c7eaa986c2777d) Predicate({ns.bse.filename}) foo_second', - f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#a8af899ecdab60dfaea8ec7f934053624c80a1054539e163f2c7eaa986c2777d) Predicate({ns.bse.filesize}) 585', - f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#b8fd7fba818254166a6043195004138ebda6923e012442f819a2c49671136c70) Predicate({ns.bse.author}) Me, myself, and I', - f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#b8fd7fba818254166a6043195004138ebda6923e012442f819a2c49671136c70) Predicate({ns.bse.filename}) bar_second', - f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#b8fd7fba818254166a6043195004138ebda6923e012442f819a2c49671136c70) Predicate({ns.bse.filesize}) 636', - f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#d43758ace82154a1cc10ca0dfef63cb20dd831f9c87edd6dc06539eefe67371d) Predicate({ns.bse.author}) Me, myself, and I', - f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#d43758ace82154a1cc10ca0dfef63cb20dd831f9c87edd6dc06539eefe67371d) Predicate({ns.bse.filename}) foo_first', - f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#d43758ace82154a1cc10ca0dfef63cb20dd831f9c87edd6dc06539eefe67371d) Predicate({ns.bse.filesize}) 546', - f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#d803187cbf3676ae9d38126270a6152c60431589aa3bb3824baf8954e9c097f1) Predicate({ns.bse.author}) Me, myself, and I', - f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#d803187cbf3676ae9d38126270a6152c60431589aa3bb3824baf8954e9c097f1) Predicate({ns.bse.filename}) td_second', - f'Node(http://bsfs.ai/schema/File, http://example.com/me/file#d803187cbf3676ae9d38126270a6152c60431589aa3bb3824baf8954e9c097f1) Predicate({ns.bse.filesize}) 703', - }) + self.assertTrue((set(outbuf.getvalue().split('\n')) - {''}).issuperset({ + f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#2f4109b40107cc50e0884755a1a961ed126887e49b8dbaf0e146b2e226aa6647) Predicate({ns.bse.author}) Me, myself, and I', + f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#2f4109b40107cc50e0884755a1a961ed126887e49b8dbaf0e146b2e226aa6647) Predicate({ns.bse.filename}) alpha_second', + f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#441f3d10c8ff489fe8e33e639606512f6c463151cc429de7e554b9af670c2ece) Predicate({ns.bse.author}) Me, myself, and I', + f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#441f3d10c8ff489fe8e33e639606512f6c463151cc429de7e554b9af670c2ece) Predicate({ns.bse.filename}) omega_second', + f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#69b98ecf7aff3e95b09688ba93331678eb8397817111f674c9558e6dd8f5e871) Predicate({ns.bse.author}) Me, myself, and I', + f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#69b98ecf7aff3e95b09688ba93331678eb8397817111f674c9558e6dd8f5e871) Predicate({ns.bse.filename}) td_first', + f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#78f7eb7f0d8221cdb2cb26c978fa42a11f75eb87becc768f4474134cb1e06926) Predicate({ns.bse.author}) Me, myself, and I', + f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#78f7eb7f0d8221cdb2cb26c978fa42a11f75eb87becc768f4474134cb1e06926) Predicate({ns.bse.filename}) testfile', + f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#80818b8ec2ee1919116dba9c8a7e0a4608313cf3b463cd88e9ed77a700dd92d3) Predicate({ns.bse.author}) Me, myself, and I', + f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#80818b8ec2ee1919116dba9c8a7e0a4608313cf3b463cd88e9ed77a700dd92d3) Predicate({ns.bse.filename}) bar_first', + f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#976d2ea0e58488678cc7e435fbfadabfb6eb6cf50ad51862f38f73729ed11795) Predicate({ns.bse.author}) Me, myself, and I', + f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#976d2ea0e58488678cc7e435fbfadabfb6eb6cf50ad51862f38f73729ed11795) Predicate({ns.bse.filename}) omega_first', + f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#997e2fbb7494a3818ec782d2bc87bf1cffafba6b9c0f658e4a6c18a723e944d3) Predicate({ns.bse.author}) Me, myself, and I', + f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#997e2fbb7494a3818ec782d2bc87bf1cffafba6b9c0f658e4a6c18a723e944d3) Predicate({ns.bse.filename}) alpha_first', + f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#a8af899ecdab60dfaea8ec7f934053624c80a1054539e163f2c7eaa986c2777d) Predicate({ns.bse.author}) Me, myself, and I', + f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#a8af899ecdab60dfaea8ec7f934053624c80a1054539e163f2c7eaa986c2777d) Predicate({ns.bse.filename}) foo_second', + f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#b8fd7fba818254166a6043195004138ebda6923e012442f819a2c49671136c70) Predicate({ns.bse.author}) Me, myself, and I', + f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#b8fd7fba818254166a6043195004138ebda6923e012442f819a2c49671136c70) Predicate({ns.bse.filename}) bar_second', + f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#d43758ace82154a1cc10ca0dfef63cb20dd831f9c87edd6dc06539eefe67371d) Predicate({ns.bse.author}) Me, myself, and I', + f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#d43758ace82154a1cc10ca0dfef63cb20dd831f9c87edd6dc06539eefe67371d) Predicate({ns.bse.filename}) foo_first', + f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#d803187cbf3676ae9d38126270a6152c60431589aa3bb3824baf8954e9c097f1) Predicate({ns.bse.author}) Me, myself, and I', + f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#d803187cbf3676ae9d38126270a6152c60431589aa3bb3824baf8954e9c097f1) Predicate({ns.bse.filename}) td_second', + f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#accb115d266ad60c53cd01a7f7130f245886ce8eaf69bc85319febc11d9fe089) Predicate({ns.bse.author}) Me, myself, and I', + f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#accb115d266ad60c53cd01a7f7130f245886ce8eaf69bc85319febc11d9fe089) Predicate({ns.bse.filename}) testimage.jpg', + # features + f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#accb115d266ad60c53cd01a7f7130f245886ce8eaf69bc85319febc11d9fe089) Predicate(https://schema.bsfs.io/ie/Node/Entity#colors_spatial_0658f2234a054e1dd59a14462c89f7733e019160419c796356aa831498bd0a04) (91, 127, 121, 94, 138, 167, 163, 134, 190, 138, 170, 156, 121, 142, 159)', + # links to previews + f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#2f4109b40107cc50e0884755a1a961ed126887e49b8dbaf0e146b2e226aa6647) Predicate({ns.bse.preview}) Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#79cb8a7e6369361a4f4cb7ff729c1ed3fcf87204769623d6fbd6ebfae601e5c7_s50)', + f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#441f3d10c8ff489fe8e33e639606512f6c463151cc429de7e554b9af670c2ece) Predicate({ns.bse.preview}) Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#a8b3245636074d5370283b690281abda8ffdff12ce8b1af77c8bc0a4c85be860_s50)', + f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#69b98ecf7aff3e95b09688ba93331678eb8397817111f674c9558e6dd8f5e871) Predicate({ns.bse.preview}) Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#968b9aa178585bc8d1fca0e4e32b8cf30b3941eff72f34e320584aaae8fd23ac_s50)', + f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#78f7eb7f0d8221cdb2cb26c978fa42a11f75eb87becc768f4474134cb1e06926) Predicate({ns.bse.preview}) Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#dbfd8ebc0557c4925e9ff8411629a74a15eca934a4c2a6bd3134dd81d2f95a36_s50)', + f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#80818b8ec2ee1919116dba9c8a7e0a4608313cf3b463cd88e9ed77a700dd92d3) Predicate({ns.bse.preview}) Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#567049149769e1d02e6af6cfee3991f7cf0cbc935cbf6a566047f40155fb13a8_s50)', + f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#976d2ea0e58488678cc7e435fbfadabfb6eb6cf50ad51862f38f73729ed11795) Predicate({ns.bse.preview}) Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#df2185d8927ccef65c92fc90b94e800b02791354d8dede9dd9aa0e2c2cb1e91e_s50)', + f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#997e2fbb7494a3818ec782d2bc87bf1cffafba6b9c0f658e4a6c18a723e944d3) Predicate({ns.bse.preview}) Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#9827509a74a60dfceed11936f7f624e9c932f66c8c0d20d355d56f8c3c9b56b1_s50)', + f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#a8af899ecdab60dfaea8ec7f934053624c80a1054539e163f2c7eaa986c2777d) Predicate({ns.bse.preview}) Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#7a975385a110c21fcd12e238fab9501550fa02f6328749068a3bffd65e291027_s50)', + f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#accb115d266ad60c53cd01a7f7130f245886ce8eaf69bc85319febc11d9fe089) Predicate({ns.bse.preview}) Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#2656e303d7218300326df73b64f312d8b37eb980358be27a38b5f63dae259be3_s50)', + f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#b8fd7fba818254166a6043195004138ebda6923e012442f819a2c49671136c70) Predicate({ns.bse.preview}) Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#a63c84e647138a2b68113474212f6aee542b3707171ff178551db3c296e59817_s50)', + f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#d43758ace82154a1cc10ca0dfef63cb20dd831f9c87edd6dc06539eefe67371d) Predicate({ns.bse.preview}) Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#26f16643b2570ac5b2d1f8c373d492cb724aae2dd8d71a0b63647838ed651254_s50)', + f'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/file#d803187cbf3676ae9d38126270a6152c60431589aa3bb3824baf8954e9c097f1) Predicate({ns.bse.preview}) Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#5d1235838c3d501204bb09c2de563d7e4a7fd17b7ec4ff302221c0e88c4741aa_s50)', + # preview dimensions + f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#2656e303d7218300326df73b64f312d8b37eb980358be27a38b5f63dae259be3_s50) Predicate({ns.bsp.height}) 33', + f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#2656e303d7218300326df73b64f312d8b37eb980358be27a38b5f63dae259be3_s50) Predicate({ns.bsp.width}) 50', + f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#26f16643b2570ac5b2d1f8c373d492cb724aae2dd8d71a0b63647838ed651254_s50) Predicate({ns.bsp.height}) 50', + f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#26f16643b2570ac5b2d1f8c373d492cb724aae2dd8d71a0b63647838ed651254_s50) Predicate({ns.bsp.width}) 36', + f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#567049149769e1d02e6af6cfee3991f7cf0cbc935cbf6a566047f40155fb13a8_s50) Predicate({ns.bsp.height}) 50', + f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#567049149769e1d02e6af6cfee3991f7cf0cbc935cbf6a566047f40155fb13a8_s50) Predicate({ns.bsp.width}) 36', + f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#5d1235838c3d501204bb09c2de563d7e4a7fd17b7ec4ff302221c0e88c4741aa_s50) Predicate({ns.bsp.height}) 50', + f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#5d1235838c3d501204bb09c2de563d7e4a7fd17b7ec4ff302221c0e88c4741aa_s50) Predicate({ns.bsp.width}) 36', + f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#79cb8a7e6369361a4f4cb7ff729c1ed3fcf87204769623d6fbd6ebfae601e5c7_s50) Predicate({ns.bsp.height}) 50', + f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#79cb8a7e6369361a4f4cb7ff729c1ed3fcf87204769623d6fbd6ebfae601e5c7_s50) Predicate({ns.bsp.width}) 36', + f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#7a975385a110c21fcd12e238fab9501550fa02f6328749068a3bffd65e291027_s50) Predicate({ns.bsp.height}) 50', + f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#7a975385a110c21fcd12e238fab9501550fa02f6328749068a3bffd65e291027_s50) Predicate({ns.bsp.width}) 36', + f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#968b9aa178585bc8d1fca0e4e32b8cf30b3941eff72f34e320584aaae8fd23ac_s50) Predicate({ns.bsp.height}) 50', + f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#968b9aa178585bc8d1fca0e4e32b8cf30b3941eff72f34e320584aaae8fd23ac_s50) Predicate({ns.bsp.width}) 36', + f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#9827509a74a60dfceed11936f7f624e9c932f66c8c0d20d355d56f8c3c9b56b1_s50) Predicate({ns.bsp.height}) 50', + f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#9827509a74a60dfceed11936f7f624e9c932f66c8c0d20d355d56f8c3c9b56b1_s50) Predicate({ns.bsp.width}) 36', + f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#a63c84e647138a2b68113474212f6aee542b3707171ff178551db3c296e59817_s50) Predicate({ns.bsp.height}) 50', + f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#a63c84e647138a2b68113474212f6aee542b3707171ff178551db3c296e59817_s50) Predicate({ns.bsp.width}) 36', + f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#a8b3245636074d5370283b690281abda8ffdff12ce8b1af77c8bc0a4c85be860_s50) Predicate({ns.bsp.height}) 50', + f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#a8b3245636074d5370283b690281abda8ffdff12ce8b1af77c8bc0a4c85be860_s50) Predicate({ns.bsp.width}) 36', + f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#dbfd8ebc0557c4925e9ff8411629a74a15eca934a4c2a6bd3134dd81d2f95a36_s50) Predicate({ns.bsp.height}) 50', + f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#dbfd8ebc0557c4925e9ff8411629a74a15eca934a4c2a6bd3134dd81d2f95a36_s50) Predicate({ns.bsp.width}) 36', + f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#df2185d8927ccef65c92fc90b94e800b02791354d8dede9dd9aa0e2c2cb1e91e_s50) Predicate({ns.bsp.height}) 50', + f'Node(https://schema.bsfs.io/ie/Node/Preview, http://example.com/me/preview#df2185d8927ccef65c92fc90b94e800b02791354d8dede9dd9aa0e2c2cb1e91e_s50) Predicate({ns.bsp.width}) 36', + # assets + # ... (not checked) + })) ## main ## diff --git a/test/apps/test_info.py b/test/apps/test_info.py index 6f4d98f..ffcaecf 100644 --- a/test/apps/test_info.py +++ b/test/apps/test_info.py @@ -1,15 +1,18 @@ -""" -Part of the bsie test suite. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 -""" -# imports +# standard imports import argparse import contextlib import io +import os +import tempfile import unittest +# external imports +import yaml + +# bsie imports +from bsie.utils import bsfs + # objects to test from bsie.apps.info import main @@ -17,17 +20,72 @@ from bsie.apps.info import main ## code ## class TestIndex(unittest.TestCase): + def setUp(self): + config = { + 'ReaderBuilder': {}, + 'ExtractorBuilder': [ + {'bsie.extractor.preview.Preview': { + 'max_sides': [50], + }}, + {'bsie.extractor.generic.path.Path': {}}, + {'bsie.extractor.generic.constant.Constant': { + 'schema': ''' + bse:author rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsn:Entity ; + rdfs:range xsd:string ; + bsfs:unique "true"^^xsd:boolean . + ''', + 'tuples': [['https://schema.bsfs.io/ie/Node/Entity#author', 'Me, myself, and I']], + }}, + {'bsie.extractor.image.colors_spatial.ColorsSpatial': { + 'width': 2, + 'height': 2, + 'exp': 2, + }}, + ] + } + # create config file + _, self.config_path = tempfile.mkstemp(prefix='bsie-test-', suffix='.yaml') + with open(self.config_path, 'wt') as cfile: + yaml.dump(config, cfile) + + def tearDown(self): + if os.path.exists(self.config_path): + os.unlink(self.config_path) + def test_predicates(self): outbuf = io.StringIO() with contextlib.redirect_stdout(outbuf): # show predicates infos - main(['predicates']) + main(['--config', self.config_path, 'predicates']) # verify output self.assertSetEqual({pred for pred in outbuf.getvalue().split('\n') if pred != ''}, { - 'http://bsfs.ai/schema/Entity#author', - 'http://bsfs.ai/schema/Predicate', - 'http://bsfs.ai/schema/Entity#filename', - 'http://bsfs.ai/schema/Entity#filesize', + 'https://schema.bsfs.io/ie/Node/Entity#author', + 'https://schema.bsfs.io/core/Predicate', + 'https://schema.bsfs.io/ie/Node/Entity#filename', + 'https://schema.bsfs.io/ie/Node/Entity#colors_spatial_0658f2234a054e1dd59a14462c89f7733e019160419c796356aa831498bd0a04', + 'https://schema.bsfs.io/ie/Node/Entity#preview', + 'https://schema.bsfs.io/ie/Node/Preview#width', + 'https://schema.bsfs.io/ie/Node/Preview#height', + 'https://schema.bsfs.io/ie/Node/Preview#asset', + }) + + def test_schema(self): + outbuf = io.StringIO() + with contextlib.redirect_stdout(outbuf): + # show schema infos + main(['--config', self.config_path, 'schema']) + # verify output + schema = bsfs.schema.from_string(outbuf.getvalue()) + self.assertSetEqual({pred.uri for pred in schema.predicates()}, { + 'https://schema.bsfs.io/ie/Node/Entity#author', + 'https://schema.bsfs.io/core/Predicate', + 'https://schema.bsfs.io/ie/Node/Entity#filename', + 'https://schema.bsfs.io/ie/Node/Entity#colors_spatial_0658f2234a054e1dd59a14462c89f7733e019160419c796356aa831498bd0a04', + 'https://schema.bsfs.io/ie/Node/Entity#preview', + 'https://schema.bsfs.io/ie/Node/Preview#width', + 'https://schema.bsfs.io/ie/Node/Preview#height', + 'https://schema.bsfs.io/ie/Node/Preview#asset', }) def test_invalid(self): diff --git a/test/apps/test_loader.py b/test/apps/test_loader.py new file mode 100644 index 0000000..4670266 --- /dev/null +++ b/test/apps/test_loader.py @@ -0,0 +1,83 @@ + +# standard imports +import os +import tempfile +import unittest + +# external imports +import yaml + +# objects to test +from bsie.apps._loader import load_pipeline + + +## code ## + +class TestLoader(unittest.TestCase): + def test_load_pipeline(self): + # config file can be empty + config = { + 'ReaderBuilder': {}, + 'ExtractorBuilder': [] + } + # create config file + _, path = tempfile.mkstemp(prefix='bsie-test-', suffix='.yaml') + with open(path, 'wt') as cfile: + yaml.dump(config, cfile) + # pipeline contains only default predicates + pipeline = load_pipeline(path) + self.assertSetEqual({pred.uri for pred in pipeline.schema.predicates()}, { + 'https://schema.bsfs.io/core/Predicate', + }) + + # pipeline is built according to configured extractors + config = { + 'ReaderBuilder': {}, + 'ExtractorBuilder': [ + {'bsie.extractor.preview.Preview': { + 'max_sides': [50], + }}, + {'bsie.extractor.generic.path.Path': {}}, + {'bsie.extractor.generic.constant.Constant': { + 'schema': ''' + bse:author rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsn:Entity ; + rdfs:range xsd:string ; + bsfs:unique "true"^^xsd:boolean . + ''', + 'tuples': [['https://schema.bsfs.io/ie/Node/Entity#author', 'Me, myself, and I']], + }}, + {'bsie.extractor.image.colors_spatial.ColorsSpatial': { + 'width': 2, + 'height': 2, + 'exp': 2, + }}, + ] + } + # create config file + _, path = tempfile.mkstemp(prefix='bsie-test-', suffix='.yaml') + with open(path, 'wt') as cfile: + yaml.dump(config, cfile) + # pipeline contains all defined predicates + pipeline = load_pipeline(path) + self.assertSetEqual({pred.uri for pred in pipeline.schema.predicates()}, { + 'https://schema.bsfs.io/ie/Node/Entity#author', + 'https://schema.bsfs.io/core/Predicate', + 'https://schema.bsfs.io/ie/Node/Entity#filename', + 'https://schema.bsfs.io/ie/Node/Entity#colors_spatial_0658f2234a054e1dd59a14462c89f7733e019160419c796356aa831498bd0a04', + 'https://schema.bsfs.io/ie/Node/Entity#preview', + 'https://schema.bsfs.io/ie/Node/Preview#width', + 'https://schema.bsfs.io/ie/Node/Preview#height', + 'https://schema.bsfs.io/ie/Node/Preview#asset', + }) + + # config file must exist + self.assertRaises(OSError, load_pipeline, 'invalid.yaml') + + +## main ## + +if __name__ == '__main__': + unittest.main() + +## EOF ## diff --git a/test/apps/test_main.py b/test/apps/test_main.py new file mode 100644 index 0000000..4fa094b --- /dev/null +++ b/test/apps/test_main.py @@ -0,0 +1,57 @@ + +# standard imports +import contextlib +import io +import json +import os +import tempfile +import unittest +import yaml + +# objects to test +from bsie.apps import main + + +## code ## + +class TestMain(unittest.TestCase): + def setUp(self): + config = { + 'ReaderBuilder': {}, + 'ExtractorBuilder': [ + {'bsie.extractor.generic.stat.Stat': {}}, + {'bsie.extractor.generic.path.Path': {}}, + ] + } + # create config file + _, self.config_path = tempfile.mkstemp(prefix='bsie-test-', suffix='.yaml') + with open(self.config_path, 'wt') as cfile: + yaml.dump(config, cfile) + + def tearDown(self): + if os.path.exists(self.config_path): + os.unlink(self.config_path) + + def test_main(self): + # must at least pass an app + with contextlib.redirect_stderr(io.StringIO()): + self.assertRaises(SystemExit, main, []) + # app takes over + with contextlib.redirect_stderr(io.StringIO()): + self.assertRaises(SystemExit, main, ['info']) + outbuf = io.StringIO() + with contextlib.redirect_stdout(outbuf): + main(['info', '--config', self.config_path, 'predicates']) + self.assertEqual(set(outbuf.getvalue().strip().split('\n')), { + 'https://schema.bsfs.io/ie/Node/Entity#filename', + 'https://schema.bsfs.io/ie/Node/Entity#filesize', + 'https://schema.bsfs.io/core/Predicate', + }) + + +## main ## + +if __name__ == '__main__': + unittest.main() + +## EOF ## diff --git a/test/apps/testdir/testimage.jpg b/test/apps/testdir/testimage.jpg Binary files differnew file mode 100644 index 0000000..c80bb48 --- /dev/null +++ b/test/apps/testdir/testimage.jpg diff --git a/test/extractor/generic/test_constant.py b/test/extractor/generic/test_constant.py index 9dbaced..77ee02b 100644 --- a/test/extractor/generic/test_constant.py +++ b/test/extractor/generic/test_constant.py @@ -1,10 +1,5 @@ -""" -Part of the bsie test suite. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 -""" -# imports +# standard imports import unittest # bsie imports @@ -20,11 +15,11 @@ class TestConstant(unittest.TestCase): def test_extract(self): schema = ''' bse:author rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:Entity ; + rdfs:domain bsn:Entity ; rdfs:range xsd:string ; bsfs:unique "true"^^xsd:boolean . bse:comment rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:Entity ; + rdfs:domain bsn:Entity ; rdfs:range xsd:string ; bsfs:unique "false"^^xsd:boolean . ''' @@ -33,33 +28,33 @@ class TestConstant(unittest.TestCase): (ns.bse.comment, 'the quick brown fox jumps over the lazy dog.'), ] ext = Constant(schema, tuples) - node = _node.Node(ns.bsfs.Entity, '') # Blank node + node = _node.Node(ns.bsn.Entity, '') # Blank node p_author = ext.schema.predicate(ns.bse.author) p_comment = ext.schema.predicate(ns.bse.comment) - entity = ext.schema.node(ns.bsfs.Node).get_child(ns.bsfs.Entity) - string = ext.schema.literal(ns.bsfs.Literal).get_child(ns.xsd.string) + entity = ext.schema.node(ns.bsfs.Node).child(ns.bsn.Entity) + string = ext.schema.literal(ns.bsfs.Literal).child(ns.xsd.string) # baseline self.assertSetEqual(set(ext.extract(node, None, (p_author, p_comment))), {(node, p_author, 'Me, myself, and I'), (node, p_comment, 'the quick brown fox jumps over the lazy dog.')}) # predicates is respected - p_foobar = ext.schema.predicate(ns.bsfs.Predicate).get_child(ns.bse.foobar, domain=entity, range=entity) + p_foobar = ext.schema.predicate(ns.bsfs.Predicate).child(ns.bse.foobar, domain=entity, range=entity) self.assertSetEqual(set(ext.extract(node, None, (p_author, p_foobar))), {(node, p_author, 'Me, myself, and I')}) self.assertSetEqual(set(ext.extract(node, None, (p_comment, p_foobar))), {(node, p_comment, 'the quick brown fox jumps over the lazy dog.')}) - p_barfoo = ext.schema.predicate(ns.bse.author).get_child(ns.bse.comment, domain=entity, range=string) + p_barfoo = ext.schema.predicate(ns.bse.author).child(ns.bse.comment, domain=entity, range=string) self.assertSetEqual(set(ext.extract(node, None, (p_foobar, p_barfoo))), set()) def test_construct(self): # schema compliance schema = ''' bse:author rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:Entity ; + rdfs:domain bsn:Entity ; rdfs:range xsd:string ; bsfs:unique "true"^^xsd:boolean . bse:comment rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:Entity ; + rdfs:domain bsn:Entity ; rdfs:range xsd:string ; bsfs:unique "false"^^xsd:boolean . ''' @@ -80,13 +75,13 @@ class TestConstant(unittest.TestCase): def test_eq(self): schema_a = ''' bse:author rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:Entity ; + rdfs:domain bsn:Entity ; rdfs:range xsd:string ; bsfs:unique "true"^^xsd:boolean . ''' schema_b = ''' bse:comment rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:Entity ; + rdfs:domain bsn:Entity ; rdfs:range xsd:string ; bsfs:unique "false"^^xsd:boolean . ''' diff --git a/test/extractor/generic/test_path.py b/test/extractor/generic/test_path.py index 820f402..0beb37e 100644 --- a/test/extractor/generic/test_path.py +++ b/test/extractor/generic/test_path.py @@ -1,14 +1,9 @@ -""" -Part of the bsie test suite. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 -""" -# imports +# standard imports import unittest # bsie imports -from bsie.base import extractor +from bsie.extractor import base from bsie.utils import bsfs, node as _node, ns # objects to test @@ -29,31 +24,31 @@ class TestPath(unittest.TestCase): def test_schema(self): self.assertEqual(Path().schema, - bsfs.schema.Schema.from_string(extractor.SCHEMA_PREAMBLE + ''' + bsfs.schema.from_string(base.SCHEMA_PREAMBLE + ''' bse:filename rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:File ; + rdfs:domain bsn:Entity ; rdfs:range xsd:string ; - bsfs:unique "false"^^xsd:boolean . + bsfs:unique "true"^^xsd:boolean . ''')) def test_extract(self): ext = Path() - node = _node.Node(ns.bsfs.File, '') # Blank node + node = _node.Node(ns.bsn.Entity, '') # Blank node content = '/tmp/foo/bar' p_filename = ext.schema.predicate(ns.bse.filename) - entity = ext.schema.node(ns.bsfs.Node).get_child(ns.bsfs.Entity) - string = ext.schema.literal(ns.bsfs.Literal).get_child(ns.xsd.string) + entity = ext.schema.node(ns.bsfs.Node).child(ns.bsn.Entity) + string = ext.schema.literal(ns.bsfs.Literal).child(ns.xsd.string) # baseline self.assertSetEqual(set(ext.extract(node, content, (p_filename, ))), {(node, p_filename, 'bar')}) # predicates parameter is respected - p_foo = ext.schema.predicate(ns.bsfs.Predicate).get_child(ns.bse.foo, domain=entity, range=string) # unsupported predicate + p_foo = ext.schema.predicate(ns.bsfs.Predicate).child(ns.bse.foo, domain=entity, range=string) # unsupported predicate self.assertSetEqual(set(ext.extract(node, content, (p_filename, p_foo))), {(node, p_filename, 'bar')}) self.assertSetEqual(set(ext.extract(node, content, (p_foo, ))), set()) # predicates are validated - p_bar = p_foo.get_child(ns.bse.filename) # same URI but different hierarchy + p_bar = p_foo.child(ns.bse.filename) # same URI but different hierarchy self.assertSetEqual(set(ext.extract(node, content, (p_filename, p_bar))), {(node, p_filename, 'bar')}) self.assertSetEqual(set(ext.extract(node, content, (p_bar, ))), set()) diff --git a/test/extractor/generic/test_stat.py b/test/extractor/generic/test_stat.py index 3441438..0e83e24 100644 --- a/test/extractor/generic/test_stat.py +++ b/test/extractor/generic/test_stat.py @@ -1,15 +1,10 @@ -""" -Part of the bsie test suite. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 -""" -# imports +# standard imports import os import unittest # bsie imports -from bsie.base import extractor +from bsie.extractor import base from bsie.utils import bsfs, node as _node, ns # objects to test @@ -30,31 +25,31 @@ class TestStat(unittest.TestCase): def test_schema(self): self.assertEqual(Stat().schema, - bsfs.schema.Schema.from_string(extractor.SCHEMA_PREAMBLE + ''' + bsfs.schema.from_string(base.SCHEMA_PREAMBLE + ''' bse:filesize rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:File ; + rdfs:domain bsn:Entity ; rdfs:range xsd:integer ; - bsfs:unique "false"^^xsd:boolean . + bsfs:unique "true"^^xsd:boolean . ''')) def test_extract(self): ext = Stat() - node = _node.Node(ns.bsfs.File, '') # Blank node + node = _node.Node(ns.bsn.Entity, '') # Blank node content = os.stat(__file__) p_filesize = ext.schema.predicate(ns.bse.filesize) - entity = ext.schema.node(ns.bsfs.Node).get_child(ns.bsfs.Entity) - string = ext.schema.literal(ns.bsfs.Literal).get_child(ns.xsd.string) + entity = ext.schema.node(ns.bsfs.Node).child(ns.bsn.Entity) + string = ext.schema.literal(ns.bsfs.Literal).child(ns.xsd.string) # baseline self.assertSetEqual(set(ext.extract(node, content, (p_filesize, ))), {(node, p_filesize, content.st_size)}) # predicates parameter is respected - p_foo = ext.schema.predicate(ns.bsfs.Predicate).get_child(ns.bse.foo, domain=entity, range=string) # unsupported predicate + p_foo = ext.schema.predicate(ns.bsfs.Predicate).child(ns.bse.foo, domain=entity, range=string) # unsupported predicate self.assertSetEqual(set(ext.extract(node, content, (p_filesize, p_foo))), {(node, p_filesize, content.st_size)}) self.assertSetEqual(set(ext.extract(node, content, (p_foo, ))), set()) # predicates are validated - p_bar = p_foo.get_child(ns.bse.filesizse) # same URI but different hierarchy + p_bar = p_foo.child(ns.bse.filesizse) # same URI but different hierarchy self.assertSetEqual(set(ext.extract(node, content, (p_filesize, p_bar))), {(node, p_filesize, content.st_size)}) self.assertSetEqual(set(ext.extract(node, content, (p_bar, ))), set()) diff --git a/test/base/__init__.py b/test/extractor/image/__init__.py index e69de29..e69de29 100644 --- a/test/base/__init__.py +++ b/test/extractor/image/__init__.py diff --git a/test/extractor/image/test_colors_spatial.py b/test/extractor/image/test_colors_spatial.py new file mode 100644 index 0000000..902ab6d --- /dev/null +++ b/test/extractor/image/test_colors_spatial.py @@ -0,0 +1,95 @@ + +# standard imports +import os +import unittest + +# external imports +import PIL.Image + +# bsie imports +from bsie.extractor import base +from bsie.utils import bsfs, ns, node as _node + +# objects to test +from bsie.extractor.image.colors_spatial import ColorsSpatial + + +## code ## + +class TestColorsSpatial(unittest.TestCase): + def setUp(self): + # content id with default constructors (width=32, height=32, exp=4) + self.instance_prefix = 'https://schema.bsfs.io/ie/Literal/Array/Feature/ColorsSpatial' + self.predicate_prefix = 'https://schema.bsfs.io/ie/Node/Entity#colors_spatial_' + self.uuid = 'adee8d6c43687021e1c5bffe56bcfe727f1638d792744137181304ef889dac2a' + + def test_essentials(self): + # clones are equal + self.assertEqual(ColorsSpatial(32, 32, 4), ColorsSpatial(32, 32, 4)) + self.assertEqual(hash(ColorsSpatial(32, 32, 4)), hash(ColorsSpatial(32, 32, 4))) + # equal respects type + self.assertNotEqual(ColorsSpatial(32, 32, 4), 'hello world') + self.assertNotEqual(hash(ColorsSpatial(32, 32, 4)), hash('hello world')) + # equals respects width + self.assertNotEqual(ColorsSpatial(32, 32, 4), ColorsSpatial(16, 32, 4)) + self.assertNotEqual(hash(ColorsSpatial(32, 32, 4)), hash(ColorsSpatial(16, 32, 4))) + # equals respects height + self.assertNotEqual(ColorsSpatial(32, 32, 4), ColorsSpatial(32, 16, 4)) + self.assertNotEqual(hash(ColorsSpatial(32, 32, 4)), hash(ColorsSpatial(32, 16, 4))) + # equals respects exp + self.assertNotEqual(ColorsSpatial(32, 32, 4), ColorsSpatial(32, 32, 8)) + self.assertNotEqual(hash(ColorsSpatial(32, 32, 4)), hash(ColorsSpatial(32, 32, 8))) + # string representation + self.assertEqual(str(ColorsSpatial()), 'ColorsSpatial') + self.assertEqual(repr(ColorsSpatial(64, 16, 2)), 'ColorsSpatial(64, 16, 2)') + + def test_dimension(self): + self.assertEqual(ColorsSpatial.dimension(32, 32, 4), 3 * (32*32 + 8*8 + 2*2)) + self.assertEqual(ColorsSpatial.dimension(16, 16, 8), 3 * (16*16 + 2*2)) + self.assertEqual(ColorsSpatial.dimension(64, 64, 16), 3 * (64*64 + 4*4)) + + def test_schema(self): + schema = bsfs.schema.from_string(base.SCHEMA_PREAMBLE + f''' + <{self.instance_prefix}> rdfs:subClassOf bsa:Feature ; + # annotations + rdfs:label "Spatially dominant colors"^^xsd:string ; + schema:description "Domiant colors of subregions in an image."^^xsd:string ; + bsfs:dtype xsd:integer . + + <{self.instance_prefix}#{self.uuid}> rdfs:subClassOf <{self.instance_prefix}> ; + bsfs:dimension "3276"^^xsd:integer ; + # annotations + <{self.instance_prefix}/args#width> "32"^^xsd:integer ; + <{self.instance_prefix}/args#height> "32"^^xsd:integer ; + <{self.instance_prefix}/args#exp> "4"^^xsd:float . + + <{self.predicate_prefix}{self.uuid}> rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsn:Entity ; + rdfs:range <{self.instance_prefix}#{self.uuid}> ; + bsfs:unique "true"^^xsd:boolean . + ''') + self.assertEqual(schema, ColorsSpatial().schema) + + def test_extract(self): + ext = ColorsSpatial(2,2,2) + img = PIL.Image.open(os.path.join(os.path.dirname(__file__), 'testimage.jpg')) + node = _node.Node(ns.bsn.Entity, bsfs.URI('http://example.com/entity#1234')) + principals = set(ext.principals) + self.assertEqual(len(principals), 1) + # valid invocation yields feature + ret = list(ext.extract(node, img, principals)) + self.assertEqual(ret[0], ( + node, + list(principals)[0], + (91, 127, 121, 94, 138, 167, 163, 134, 190, 138, 170, 156, 121, 142, 159))) + # principals is respected + self.assertListEqual(list(ext.extract(node, img, {})), []) + + + +## main ## + +if __name__ == '__main__': + unittest.main() + +## EOF ## diff --git a/test/extractor/image/test_photometrics.py b/test/extractor/image/test_photometrics.py new file mode 100644 index 0000000..fb219e2 --- /dev/null +++ b/test/extractor/image/test_photometrics.py @@ -0,0 +1,143 @@ + +# standard imports +import unittest + +# bsie imports +from bsie.extractor import base +from bsie.utils import bsfs, node as _node, ns + +# objects to test +from bsie.extractor.image.photometrics import Exif, _gps_to_dec + + +## code ## + +class TestExif(unittest.TestCase): + + def test_gps_to_dec(self): + # deg+min+sec format + self.assertAlmostEqual(_gps_to_dec('29/1 58/1 45/1'.split()), 29.979167, 6) + self.assertAlmostEqual(_gps_to_dec('31 08 03'.split()), 31.134167, 6) + self.assertAlmostEqual(_gps_to_dec('20 40 586/10'.split()), 20.682944, 6) + self.assertAlmostEqual(_gps_to_dec('88/1 34 68/10'.split()), 88.568556, 6) + # deg+min format + self.assertAlmostEqual(_gps_to_dec('13 472167/10000 0/1 '.split()), 13.786945, 6) + self.assertAlmostEqual(_gps_to_dec('104/1 3215/100 0/1'.split()), 104.535833, 6) + + def test_eq(self): + # identical instances are equal + self.assertEqual(Exif(), Exif()) + self.assertEqual(hash(Exif()), hash(Exif())) + # comparison respects type + class Foo(): pass + self.assertNotEqual(Exif(), Foo()) + self.assertNotEqual(hash(Exif()), hash(Foo())) + self.assertNotEqual(Exif(), 1234) + self.assertNotEqual(hash(Exif()), hash(1234)) + self.assertNotEqual(Exif(), None) + self.assertNotEqual(hash(Exif()), hash(None)) + + def test_schema(self): + self.assertSetEqual({pred.uri for pred in Exif().schema.predicates()}, { + ns.bsfs.Predicate, + ns.bse.exposure, + ns.bse.aperture, + ns.bse.iso, + ns.bse.focal_length, + ns.bse.width, + ns.bse.height, + ns.bse.orientation, + ns.bse.orientation_label, + ns.bse.altitude, + ns.bse.latitude, + ns.bse.longitude, + }) + + def test_extract(self): + ext = Exif() + node = _node.Node(ns.bsfs.File, '') # Blank node + content = { + 'Exif.Photo.ExposureTime': '10/600', + 'Exif.Photo.FNumber': '48/10', + 'Exif.Photo.ISOSpeedRatings': '400', + 'Exif.Photo.FocalLength': '460/10', + 'Exif.Photo.PixelXDimension': '4288', + 'Exif.Photo.PixelYDimension': '2848', + 'Exif.Image.Orientation': '1', + 'Exif.GPSInfo.GPSAltitude': '431/1', + 'Exif.GPSInfo.GPSLatitude': '46/1 11397/625 0/1', + 'Exif.GPSInfo.GPSLongitude': '7/1 131250/2500 0/1', + } + + # invalid principals are ignored + self.assertSetEqual(set(ext.extract(node, content, {ns.bse.filename})), set()) + # extract finds all relevant information + self.assertSetEqual(set(ext.extract(node, content, {ext.schema.predicate(ns.bse.exposure)})), + {(node, ext.schema.predicate(ns.bse.exposure), 60.0)}) + self.assertSetEqual(set(ext.extract(node, content, {ext.schema.predicate(ns.bse.aperture)})), + {(node, ext.schema.predicate(ns.bse.aperture), 4.8)}) + self.assertSetEqual(set(ext.extract(node, content, {ext.schema.predicate(ns.bse.iso)})), + {(node, ext.schema.predicate(ns.bse.iso), 400)}) + self.assertSetEqual(set(ext.extract(node, content, {ext.schema.predicate(ns.bse.focal_length)})), + {(node, ext.schema.predicate(ns.bse.focal_length), 46.0)}) + self.assertSetEqual(set(ext.extract(node, content, {ext.schema.predicate(ns.bse.width)})), + {(node, ext.schema.predicate(ns.bse.width), 4288)}) + self.assertSetEqual(set(ext.extract(node, content, {ext.schema.predicate(ns.bse.height)})), + {(node, ext.schema.predicate(ns.bse.height), 2848)}) + self.assertSetEqual(set(ext.extract(node, content, {ext.schema.predicate(ns.bse.orientation)})), + {(node, ext.schema.predicate(ns.bse.orientation), 1)}) + self.assertSetEqual(set(ext.extract(node, content, {ext.schema.predicate(ns.bse.orientation_label)})), + {(node, ext.schema.predicate(ns.bse.orientation_label), 'landscape')}) + self.assertSetEqual(set(ext.extract(node, content, {ext.schema.predicate(ns.bse.altitude)})), + {(node, ext.schema.predicate(ns.bse.altitude), 431.0)}) + self.assertSetEqual(set(ext.extract(node, content, {ext.schema.predicate(ns.bse.latitude)})), + {(node, ext.schema.predicate(ns.bse.latitude), 46.30392)}) + self.assertSetEqual(set(ext.extract(node, content, {ext.schema.predicate(ns.bse.longitude)})), + {(node, ext.schema.predicate(ns.bse.longitude), 7.875)}) + + # check orientation label + self.assertSetEqual(set(ext.extract( + node, { + 'Exif.Photo.PixelXDimension': '4288', + 'Exif.Photo.PixelYDimension': '2848', + 'Exif.Image.Orientation': '5', + }, + {ext.schema.predicate(ns.bse.orientation_label)})), + {(node, ext.schema.predicate(ns.bse.orientation_label), 'portrait')}) + + # can pass multiple principals + self.assertSetEqual(set(ext.extract(node, content, { + ext.schema.predicate(ns.bse.exposure), + ext.schema.predicate(ns.bse.iso), + ext.schema.predicate(ns.bse.focal_length), + })), { + (node, ext.schema.predicate(ns.bse.exposure), 60.0), + (node, ext.schema.predicate(ns.bse.iso), 400), + (node, ext.schema.predicate(ns.bse.focal_length), 46.0), + }) + + # principals w/o content are ignored + self.assertSetEqual(set(ext.extract( + node, + content={'Exif.Photo.ExposureTime': '10/600'}, + principals={ + ext.schema.predicate(ns.bse.exposure), + ext.schema.predicate(ns.bse.iso), + ext.schema.predicate(ns.bse.focal_length), + }) + ), { + (node, ext.schema.predicate(ns.bse.exposure), 60.0), + }) + + # empty content is acceptable + self.assertSetEqual(set(ext.extract(node, {}, set(ext.principals))), set()) + # no principals is acceptable + self.assertSetEqual(set(ext.extract(node, content, set())), set()) + + +## main ## + +if __name__ == '__main__': + unittest.main() + +## EOF ## diff --git a/test/extractor/image/testimage.jpg b/test/extractor/image/testimage.jpg Binary files differnew file mode 100644 index 0000000..c80bb48 --- /dev/null +++ b/test/extractor/image/testimage.jpg diff --git a/test/base/test_extractor.py b/test/extractor/test_base.py index 30974ef..81865e1 100644 --- a/test/base/test_extractor.py +++ b/test/extractor/test_base.py @@ -1,30 +1,25 @@ -""" -Part of the bsie test suite. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 -""" -# imports +# standard imports import unittest # bsie imports from bsie.utils import bsfs, ns # objects to test -from bsie.base import extractor +from bsie.extractor import base ## code ## -class StubExtractor(extractor.Extractor): +class StubExtractor(base.Extractor): def __init__(self): - super().__init__(bsfs.schema.Schema.from_string(extractor.SCHEMA_PREAMBLE + ''' + super().__init__(bsfs.schema.from_string(base.SCHEMA_PREAMBLE + ''' bse:author rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:Entity ; + rdfs:domain bsn:Entity ; rdfs:range xsd:string ; bsfs:unique "false"^^xsd:boolean . bse:comment rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:Entity ; + rdfs:domain bsn:Entity ; rdfs:range xsd:string ; bsfs:unique "false"^^xsd:boolean . ''')) @@ -52,11 +47,11 @@ class TestExtractor(unittest.TestCase): self.assertNotEqual(hash(ext), hash(sub)) def test_principals(self): - schema = bsfs.schema.Schema.Empty() - entity = schema.node(ns.bsfs.Node).get_child(ns.bsfs.Entity) - string = schema.literal(ns.bsfs.Literal).get_child(bsfs.URI('http://www.w3.org/2001/XMLSchema#string')) - p_author = schema.predicate(ns.bsfs.Predicate).get_child(ns.bse.author, domain=entity, range=string) - p_comment = schema.predicate(ns.bsfs.Predicate).get_child(ns.bse.comment, domain=entity, range=string) + schema = bsfs.schema.Schema() + entity = schema.node(ns.bsfs.Node).child(ns.bsn.Entity) + string = schema.literal(ns.bsfs.Literal).child(ns.xsd.string) + p_author = schema.predicate(ns.bsfs.Predicate).child(ns.bse.author, domain=entity, range=string) + p_comment = schema.predicate(ns.bsfs.Predicate).child(ns.bse.comment, domain=entity, range=string) ext = StubExtractor() self.assertSetEqual(set(ext.principals), {p_author, p_comment} | set(schema.predicates()) - {schema.predicate(ns.bsfs.Predicate)}) diff --git a/test/extractor/test_builder.py b/test/extractor/test_builder.py new file mode 100644 index 0000000..fbb0895 --- /dev/null +++ b/test/extractor/test_builder.py @@ -0,0 +1,98 @@ + +# standard imports +import unittest + +# bsie imports +from bsie.utils import errors + +# objects to test +from bsie.extractor import ExtractorBuilder + + +## code ## + +class TestExtractorBuilder(unittest.TestCase): + def test_iter(self): + # no specifications + self.assertListEqual(list(ExtractorBuilder([])), []) + # some specifications + builder = ExtractorBuilder([ + {'bsie.extractor.generic.path.Path': {}}, + {'bsie.extractor.generic.stat.Stat': {}}, + {'bsie.extractor.generic.path.Path': {}}, + ]) + self.assertListEqual(list(builder), [0, 1, 2]) + + def test_build(self): + # simple and repeated extractors + builder = ExtractorBuilder([ + {'bsie.extractor.generic.path.Path': {}}, + {'bsie.extractor.generic.stat.Stat': {}}, + {'bsie.extractor.generic.path.Path': {}}, + ]) + ext = [builder.build(0), builder.build(1), builder.build(2)] + import bsie.extractor.generic.path + import bsie.extractor.generic.stat + self.assertListEqual(ext, [ + bsie.extractor.generic.path.Path(), + bsie.extractor.generic.stat.Stat(), + bsie.extractor.generic.path.Path(), + ]) + # out-of-bounds raises KeyError + self.assertRaises(IndexError, builder.build, 3) + + # building with args + builder = ExtractorBuilder([ + {'bsie.extractor.generic.constant.Constant': { + 'schema': ''' + bse:author rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsn:Entity ; + rdfs:range xsd:string ; + bsfs:unique "true"^^xsd:boolean . + bse:rating rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsn:Entity ; + rdfs:range xsd:integer ; + bsfs:unique "true"^^xsd:boolean . + ''', + 'tuples': [ + ('https://schema.bsfs.io/ie/Node/Entity#author', 'Me, myself, and I'), + ('https://schema.bsfs.io/ie/Node/Entity#rating', 123), + ], + }}]) + obj = builder.build(0) + import bsie.extractor.generic.constant + self.assertEqual(obj, bsie.extractor.generic.constant.Constant(''' + bse:author rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsn:Entity ; + rdfs:range xsd:string ; + bsfs:unique "true"^^xsd:boolean . + bse:rating rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsn:Entity ; + rdfs:range xsd:integer ; + bsfs:unique "true"^^xsd:boolean . + ''', [ + ('https://schema.bsfs.io/ie/Node/Entity#author', 'Me, myself, and I'), + ('https://schema.bsfs.io/ie/Node/Entity#rating', 123), + ])) + + # building with invalid args + self.assertRaises(errors.BuilderError, ExtractorBuilder( + [{'bsie.extractor.generic.path.Path': {'foo': 123}}]).build, 0) + # non-dict build specification + self.assertRaises(TypeError, ExtractorBuilder( + [('bsie.extractor.generic.path.Path', {})]).build, 0) + # multiple keys per build specification + self.assertRaises(TypeError, ExtractorBuilder( + [{'bsie.extractor.generic.path.Path': {}, + 'bsie.extractor.generic.stat.Stat': {}}]).build, 0) + # non-dict value for kwargs + self.assertRaises(TypeError, ExtractorBuilder( + [{'bsie.extractor.generic.path.Path': 123}]).build, 0) + + +## main ## + +if __name__ == '__main__': + unittest.main() + +## EOF ## diff --git a/test/extractor/test_preview.py b/test/extractor/test_preview.py new file mode 100644 index 0000000..6526783 --- /dev/null +++ b/test/extractor/test_preview.py @@ -0,0 +1,123 @@ + +# standard imports +import io +import os +import unittest + +# external imports +import PIL.Image + +# bsie imports +from bsie.extractor import base +from bsie.utils import bsfs, node as _node, ns +from bsie.reader.preview import Preview as Reader + +# objects to test +from bsie.extractor.preview import Preview + + +## code ## + +class TestPreview(unittest.TestCase): + def test_eq(self): + # identical instances are equal + self.assertEqual(Preview([1,2,3]), Preview([1,2,3])) + self.assertEqual(hash(Preview([1,2,3])), hash(Preview([1,2,3]))) + # comparison respects max_sides + self.assertNotEqual(Preview([1,2,3]), Preview([1,2])) + self.assertNotEqual(hash(Preview([1,2,3])), hash(Preview([1,2]))) + self.assertNotEqual(Preview([1,2]), Preview([1,2,3])) + self.assertNotEqual(hash(Preview([1,2])), hash(Preview([1,2,3]))) + # comparison respects type + class Foo(): pass + self.assertNotEqual(Preview([1,2,3]), Foo()) + self.assertNotEqual(hash(Preview([1,2,3])), hash(Foo())) + self.assertNotEqual(Preview([1,2,3]), 123) + self.assertNotEqual(hash(Preview([1,2,3])), hash(123)) + self.assertNotEqual(Preview([1,2,3]), None) + self.assertNotEqual(hash(Preview([1,2,3])), hash(None)) + + def test_schema(self): + self.assertEqual(Preview([1,2,3]).schema, + bsfs.schema.from_string(base.SCHEMA_PREAMBLE + ''' + bsn:Preview rdfs:subClassOf bsfs:Node . + bsl:BinaryBlob rdfs:subClassOf bsfs:Literal . + <https://schema.bsfs.io/ie/Literal/BinaryBlob/JPEG> rdfs:subClassOf bsl:BinaryBlob . + + bse:preview rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsn:Entity ; + rdfs:range bsn:Preview ; + bsfs:unique "false"^^xsd:boolean . + + bsp:width rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsn:Preview ; + rdfs:range xsd:integer ; + bsfs:unique "true"^^xsd:boolean . + + bsp:height rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsn:Preview ; + rdfs:range xsd:integer ; + bsfs:unique "true"^^xsd:boolean . + + bsp:asset rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsn:Preview ; + rdfs:range <https://schema.bsfs.io/ie/Literal/BinaryBlob/JPEG> ; + bsfs:unique "true"^^xsd:boolean . + + ''')) + + def test_extract(self): + # setup dependents + rdr = Reader() + subject = _node.Node(ns.bsn.Entity) + path = os.path.join(os.path.dirname(__file__), 'testimage.jpg') + + # setup extractor + ext = Preview(max_sides=[10]) + principals = set(ext.principals) + self.assertEqual(principals, {ext.schema.predicate(ns.bse.preview)}) + # skip unknown predicates + gen = rdr(path) + self.assertSetEqual(set(), set(ext.extract(subject, gen, + {ext.schema.predicate(ns.bsfs.Predicate).child(ns.bse.unknown)}))) + gen(10) # NOTE: consume some image to avoid resource error warning + # extract a preview + triples = set(ext.extract(subject, rdr(path), principals)) + thumbs = {node for node, _, _ in triples if node.node_type == ns.bsn.Preview} + self.assertEqual(len(thumbs), 1) + thumb = list(thumbs)[0] + # test properties + self.assertTrue(triples.issuperset({ + (subject, ext.schema.predicate(ns.bse.preview), thumb), + (thumb, ext.schema.predicate(ns.bsp.width), 10), + (thumb, ext.schema.predicate(ns.bsp.height), 10), + })) + # test image data + rawdata = {val for _, pred, val in triples if pred == ext.schema.predicate(ns.bsp.asset)} + self.assertEqual(len(rawdata), 1) + data = io.BytesIO(list(rawdata)[0]) + data.seek(0) + img = PIL.Image.open(data) + self.assertEqual(img.size, (10, 10)) + self.assertEqual(sum(band for pix in img.getdata() for band in pix), 0) + + # setup extractor + ext = Preview(max_sides=[10, 20]) + principals = set(ext.principals) + self.assertEqual(principals, {ext.schema.predicate(ns.bse.preview)}) + # extract a preview + triples = set(ext.extract(subject, rdr(path), principals)) + thumbs = {node for node, _, _ in triples if node.node_type == ns.bsn.Preview} + self.assertEqual(len(thumbs), 2) + self.assertSetEqual({10, 20}, { + value for _, pred, value in triples if pred == ext.schema.predicate(ns.bsp.width)}) + self.assertSetEqual({10, 20}, { + value for _, pred, value in triples if pred == ext.schema.predicate(ns.bsp.height)}) + + +## main ## + +if __name__ == '__main__': + unittest.main() + +## EOF ## diff --git a/test/extractor/testimage.jpg b/test/extractor/testimage.jpg Binary files differnew file mode 100644 index 0000000..4c2aca5 --- /dev/null +++ b/test/extractor/testimage.jpg diff --git a/test/lib/test_bsie.py b/test/lib/test_bsie.py index 771a0c2..0c393cc 100644 --- a/test/lib/test_bsie.py +++ b/test/lib/test_bsie.py @@ -1,16 +1,13 @@ -""" -Part of the bsie test suite. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 -""" -# imports +# standard imports import os import unittest # bsie imports -from bsie.base import extractor -from bsie.tools import builder +from bsie.extractor import ExtractorBuilder +from bsie.extractor.base import SCHEMA_PREAMBLE +from bsie.lib import PipelineBuilder, DefaultNamingPolicy +from bsie.reader import ReaderBuilder from bsie.utils import bsfs, node, ns # objects to test @@ -22,53 +19,53 @@ from bsie.lib.bsie import BSIE class TestBSIE(unittest.TestCase): def setUp(self): # reader builder - rbuild = builder.ReaderBuilder({}) + rbuild = ReaderBuilder({}) # extractor builder - ebuild = builder.ExtractorBuilder([ + ebuild = ExtractorBuilder([ {'bsie.extractor.generic.path.Path': {}}, {'bsie.extractor.generic.stat.Stat': {}}, {'bsie.extractor.generic.constant.Constant': dict( - tuples=[('http://bsfs.ai/schema/Entity#author', 'Me, myself, and I')], + tuples=[('https://schema.bsfs.io/ie/Node/Entity#author', 'Me, myself, and I')], schema=''' bse:author rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:Entity ; + rdfs:domain bsn:Entity ; rdfs:range xsd:string ; bsfs:unique "true"^^xsd:boolean . ''', )}, ]) # build pipeline - self.prefix = bsfs.Namespace('http://example.com/local/') - pbuild = builder.PipelineBuilder(self.prefix, rbuild, ebuild) + self.naming_policy = DefaultNamingPolicy(host='http://example.com/local', user='me') + pbuild = PipelineBuilder(rbuild, ebuild) self.pipeline = pbuild.build() def test_construction(self): - # pipeline only - lib = BSIE(self.pipeline) + # only pipeline and naming policy + lib = BSIE(self.pipeline, self.naming_policy) self.assertSetEqual(set(lib.principals), { ns.bse.filename, ns.bse.filesize, ns.bse.author, }) - self.assertEqual(lib.schema, bsfs.schema.Schema.from_string(extractor.SCHEMA_PREAMBLE + ''' + self.assertEqual(lib.schema, bsfs.schema.from_string(SCHEMA_PREAMBLE + ''' bse:filename rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:File ; + rdfs:domain bsn:Entity ; rdfs:range xsd:string ; - bsfs:unique "false"^^xsd:boolean . + bsfs:unique "true"^^xsd:boolean . bse:filesize rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:File ; + rdfs:domain bsn:Entity ; rdfs:range xsd:integer; - bsfs:unique "false"^^xsd:boolean . + bsfs:unique "true"^^xsd:boolean . bse:author rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:Entity ; + rdfs:domain bsn:Entity ; rdfs:range xsd:string ; bsfs:unique "true"^^xsd:boolean . ''')) # specify collect - lib = BSIE(self.pipeline, collect={ + lib = BSIE(self.pipeline, self.naming_policy, collect={ ns.bse.filesize, ns.bse.author, ns.bse.inexistent, @@ -77,44 +74,44 @@ class TestBSIE(unittest.TestCase): ns.bse.filesize, ns.bse.author, }) - self.assertEqual(lib.schema, bsfs.schema.Schema.from_string(extractor.SCHEMA_PREAMBLE + ''' + self.assertEqual(lib.schema, bsfs.schema.from_string(SCHEMA_PREAMBLE + ''' bse:filesize rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:File ; + rdfs:domain bsn:Entity ; rdfs:range xsd:integer; - bsfs:unique "false"^^xsd:boolean . + bsfs:unique "true"^^xsd:boolean . bse:author rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:Entity ; + rdfs:domain bsn:Entity ; rdfs:range xsd:string ; bsfs:unique "true"^^xsd:boolean . ''')) # empty collect is disregarded - lib = BSIE(self.pipeline, collect={}) + lib = BSIE(self.pipeline, self.naming_policy, collect={}) self.assertSetEqual(set(lib.principals), { ns.bse.filename, ns.bse.filesize, ns.bse.author, }) - self.assertEqual(lib.schema, bsfs.schema.Schema.from_string(extractor.SCHEMA_PREAMBLE + ''' + self.assertEqual(lib.schema, bsfs.schema.from_string(SCHEMA_PREAMBLE + ''' bse:filename rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:File ; + rdfs:domain bsn:Entity ; rdfs:range xsd:string ; - bsfs:unique "false"^^xsd:boolean . + bsfs:unique "true"^^xsd:boolean . bse:filesize rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:File ; + rdfs:domain bsn:Entity ; rdfs:range xsd:integer; - bsfs:unique "false"^^xsd:boolean . + bsfs:unique "true"^^xsd:boolean . bse:author rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:Entity ; + rdfs:domain bsn:Entity ; rdfs:range xsd:string ; bsfs:unique "true"^^xsd:boolean . ''')) # specify discard - lib = BSIE(self.pipeline, discard={ + lib = BSIE(self.pipeline, self.naming_policy, discard={ ns.bse.filesize, ns.bse.filename, ns.bse.inexistent, @@ -122,40 +119,40 @@ class TestBSIE(unittest.TestCase): self.assertSetEqual(set(lib.principals), { ns.bse.author, }) - self.assertEqual(lib.schema, bsfs.schema.Schema.from_string(extractor.SCHEMA_PREAMBLE + ''' + self.assertEqual(lib.schema, bsfs.schema.from_string(SCHEMA_PREAMBLE + ''' bse:author rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:Entity ; + rdfs:domain bsn:Entity ; rdfs:range xsd:string ; bsfs:unique "true"^^xsd:boolean . ''')) # specify collect and discard - lib = BSIE(self.pipeline, + lib = BSIE(self.pipeline, self.naming_policy, collect={ns.bse.filesize, ns.bse.author, ns.bse.foo, ns.bse.bar}, discard={ns.bse.author, ns.bse.foo, ns.bse.foobar}, ) self.assertSetEqual(set(lib.principals), { ns.bse.filesize, }) - self.assertEqual(lib.schema, bsfs.schema.Schema.from_string(extractor.SCHEMA_PREAMBLE + ''' + self.assertEqual(lib.schema, bsfs.schema.from_string(SCHEMA_PREAMBLE + ''' bse:filesize rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:File ; + rdfs:domain bsn:Entity ; rdfs:range xsd:integer; - bsfs:unique "false"^^xsd:boolean . + bsfs:unique "true"^^xsd:boolean . ''')) def test_from_file(self): # setup - lib = BSIE(self.pipeline) + lib = BSIE(self.pipeline, self.naming_policy) self.assertSetEqual(set(lib.principals), { ns.bse.filesize, ns.bse.filename, ns.bse.author, }) content_hash = 'a948904f2f0f479b8f8197694b30184b0d2ed1c1cd2a1ec0fb85d299a192a447' - subject = node.Node(ns.bsfs.File, (self.prefix + 'file#')[content_hash]) + subject = node.Node(ns.bsn.Entity, uri=f'http://example.com/local/me/file#{content_hash}') testfile = os.path.join(os.path.dirname(__file__), 'testfile.t') # from_file extracts all available triples diff --git a/test/lib/test_builder.py b/test/lib/test_builder.py new file mode 100644 index 0000000..3ecb3d3 --- /dev/null +++ b/test/lib/test_builder.py @@ -0,0 +1,101 @@ + +# standard imports +import logging +import unittest + +# bsie imports +from bsie.extractor import ExtractorBuilder +from bsie.reader import ReaderBuilder +from bsie.utils import bsfs + +# objects to test +from bsie.lib import PipelineBuilder + + +## code ## + +class TestPipelineBuilder(unittest.TestCase): + def test_build(self): + c_schema = ''' + bse:author rdfs:subClassOf bsfs:Predicate ; + rdfs:domain bsn:Entity ; + rdfs:range xsd:string ; + bsfs:unique "true"^^xsd:boolean . + ''' + c_tuples = [('https://schema.bsfs.io/ie/Node/Entity#author', 'Me, myself, and I')] + # prepare builders + rbuild = ReaderBuilder({}) + ebuild = ExtractorBuilder([ + {'bsie.extractor.generic.path.Path': {}}, + {'bsie.extractor.generic.stat.Stat': {}}, + {'bsie.extractor.generic.constant.Constant': dict( + schema=c_schema, + tuples=c_tuples, + )}, + ]) + # build pipeline + builder = PipelineBuilder(rbuild, ebuild) + pipeline = builder.build() + # delayed import + import bsie.reader.path + import bsie.reader.stat + import bsie.extractor.generic.path + import bsie.extractor.generic.stat + import bsie.extractor.generic.constant + # check pipeline + self.assertDictEqual(pipeline._ext2rdr, { + bsie.extractor.generic.path.Path(): bsie.reader.path.Path(), + bsie.extractor.generic.stat.Stat(): bsie.reader.stat.Stat(), + bsie.extractor.generic.constant.Constant(c_schema, c_tuples): None, + }) + + # fail to load extractor + ebuild_err = ExtractorBuilder([ + {'bsie.extractor.generic.foo.Foo': {}}, + {'bsie.extractor.generic.path.Path': {}}, + ]) + with self.assertLogs(logging.getLogger('bsie.lib.builder'), logging.ERROR): + pipeline = PipelineBuilder(rbuild, ebuild_err).build() + self.assertDictEqual(pipeline._ext2rdr, { + bsie.extractor.generic.path.Path(): bsie.reader.path.Path()}) + + # fail to build extractor + ebuild_err = ExtractorBuilder([ + {'bsie.extractor.generic.path.Path': {'foo': 123}}, + {'bsie.extractor.generic.path.Path': {}}, + ]) + with self.assertLogs(logging.getLogger('bsie.lib.builder'), logging.ERROR): + pipeline = PipelineBuilder(rbuild, ebuild_err).build() + self.assertDictEqual(pipeline._ext2rdr, { + bsie.extractor.generic.path.Path(): bsie.reader.path.Path()}) + + # fail to load reader + with self.assertLogs(logging.getLogger('bsie.lib.builder'), logging.ERROR): + # switch reader of an extractor + old_reader = bsie.extractor.generic.path.Path.CONTENT_READER + bsie.extractor.generic.path.Path.CONTENT_READER = 'bsie.reader.foo.Foo' + # build pipeline with invalid reader reference + pipeline = PipelineBuilder(rbuild, ebuild).build() + self.assertDictEqual(pipeline._ext2rdr, { + bsie.extractor.generic.stat.Stat(): bsie.reader.stat.Stat(), + bsie.extractor.generic.constant.Constant(c_schema, c_tuples): None, + }) + # switch back + bsie.extractor.generic.path.Path.CONTENT_READER = old_reader + + # fail to build reader + rbuild_err = ReaderBuilder({'bsie.reader.stat.Stat': dict(foo=123)}) + with self.assertLogs(logging.getLogger('bsie.lib.builder'), logging.ERROR): + pipeline = PipelineBuilder(rbuild_err, ebuild).build() + self.assertDictEqual(pipeline._ext2rdr, { + bsie.extractor.generic.path.Path(): bsie.reader.path.Path(), + bsie.extractor.generic.constant.Constant(c_schema, c_tuples): None, + }) + + +## main ## + +if __name__ == '__main__': + unittest.main() + +## EOF ## diff --git a/test/lib/test_naming_policy.py b/test/lib/test_naming_policy.py new file mode 100644 index 0000000..c9b0cd2 --- /dev/null +++ b/test/lib/test_naming_policy.py @@ -0,0 +1,115 @@ + +# standard imports +import unittest + +# bsie imports +from bsie.utils import ns, errors +from bsie.utils.bsfs import URI +from bsie.utils.node import Node + +# objects to test +from bsie.lib.naming_policy import NamingPolicy, NamingPolicyIterator, DefaultNamingPolicy + + + +## code ## + +class TestDefaultNamingPolicy(unittest.TestCase): + + def test_handle_node(self): + # setup + policy = DefaultNamingPolicy('http://example.com', 'me') + # handle_node doesn't modify existing uris + self.assertEqual(policy.handle_node( + Node(ns.bsn.Invalid, uri='http://example.com/you/foo#bar')).uri, + URI('http://example.com/you/foo#bar')) + # processes bsfs:File + self.assertEqual(policy.handle_node( + Node(ns.bsn.Entity, ucid='abc123cba')).uri, + URI('http://example.com/me/file#abc123cba')) + # processes bsfs:Preview + self.assertEqual(policy.handle_node( + Node(ns.bsn.Preview, ucid='abc123cba', size=123)).uri, + URI('http://example.com/me/preview#abc123cba_s123')) + # raises an exception on unknown types + self.assertRaises(errors.ProgrammingError, policy.handle_node, + Node(ns.bsn.Invalid, ucid='abc123cba', size=123)) + + def test_name_file(self): + # setup + policy = DefaultNamingPolicy('http://example.com', 'me') + # name_file uses ucid + self.assertEqual(policy.name_file( + Node(ns.bsn.Entity, ucid='123abc321')).uri, + URI('http://example.com/me/file#123abc321')) + # name_file falls back to a random guid + self.assertTrue(policy.name_file( + Node(ns.bsn.Entity)).uri.startswith('http://example.com/me/file#')) + + def test_name_preview(self): + # setup + policy = DefaultNamingPolicy('http://example.com', 'me') + # name_preview uses ucid + self.assertEqual(policy.name_preview( + Node(ns.bsn.Preview, ucid='123abc321')).uri, + URI('http://example.com/me/preview#123abc321')) + self.assertEqual(policy.name_preview( + Node(ns.bsn.Preview, ucid='123abc321', size=400)).uri, + URI('http://example.com/me/preview#123abc321_s400')) + # name_preview uses source + self.assertEqual(policy.name_preview( + Node(ns.bsn.Preview, source=Node(ns.bsn.Entity, ucid='123file321'))).uri, + URI('http://example.com/me/preview#123file321')) + self.assertEqual(policy.name_preview( + Node(ns.bsn.Preview, source=Node(ns.bsn.Entity, ucid='123file321'), size=300)).uri, + URI('http://example.com/me/preview#123file321_s300')) + # name_preview falls back to a random guid + self.assertTrue(policy.name_preview( + Node(ns.bsn.Preview)).uri.startswith('http://example.com/me/preview#')) + self.assertTrue(policy.name_preview( + Node(ns.bsn.Preview, size=200)).uri.startswith('http://example.com/me/preview#')) + self.assertTrue(policy.name_preview( + Node(ns.bsn.Preview, size=200)).uri.endswith('_s200')) + + +class TestNamingPolicyIterator(unittest.TestCase): + + def test_call(self): # NOTE: We test NamingPolicy.__call__ here + # setup + policy = DefaultNamingPolicy('http://example.com', 'me') + # call accepts list + triples = [('node', 'pred', 'value'), ('node', 'pred', 'value')] + it = policy(triples) + self.assertIsInstance(it, NamingPolicyIterator) + self.assertEqual(it._iterable, triples) + self.assertEqual(it._policy, policy) + # call accepts iterator + triples = iter([('node', 'pred', 'value'), ('node', 'pred', 'value')]) + it = policy(triples) + self.assertIsInstance(it, NamingPolicyIterator) + self.assertEqual(it._iterable, triples) + self.assertEqual(it._policy, policy) + + def test_iter(self): + # setup + policy = DefaultNamingPolicy('http://example.com', 'me') + triples = [ + (Node(ns.bsn.Entity, ucid='foo'), 'predA', 'hello'), + (Node(ns.bsn.Preview, ucid='bar'), 'predB', 1234), + (Node(ns.bsn.Preview, ucid='hello'), 'predC', Node(ns.bsn.Entity, ucid='world')) + ] + # handles nodes, handles values, ignores predicate + self.assertListEqual(list(policy(triples)), [ + (Node(ns.bsn.Entity, uri='http://example.com/me/file#foo'), 'predA', 'hello'), + (Node(ns.bsn.Preview, uri='http://example.com/me/preview#bar'), 'predB', 1234), + (Node(ns.bsn.Preview, uri='http://example.com/me/preview#hello'), 'predC', + Node(ns.bsn.Entity, uri='http://example.com/me/file#world')), + ]) + + +## main ## + +if __name__ == '__main__': + unittest.main() + +## EOF ## diff --git a/test/tools/test_pipeline.py b/test/lib/test_pipeline.py index a116a30..eb088a9 100644 --- a/test/tools/test_pipeline.py +++ b/test/lib/test_pipeline.py @@ -1,17 +1,11 @@ -""" -Part of the bsie test suite. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 -""" -# imports +# standard imports import logging import os import unittest # bsie imports -from bsie.base import errors -from bsie.utils import bsfs, node, ns +from bsie.utils import bsfs, errors, node, ns import bsie.extractor.generic.constant import bsie.extractor.generic.path import bsie.extractor.generic.stat @@ -19,7 +13,7 @@ import bsie.reader.path import bsie.reader.stat # objects to test -from bsie.tools.pipeline import Pipeline +from bsie.lib.pipeline import Pipeline ## code ## @@ -29,19 +23,19 @@ class TestPipeline(unittest.TestCase): # constant A csA = ''' bse:author rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:File ; + rdfs:domain bsn:Entity ; rdfs:range xsd:string ; bsfs:unique "true"^^xsd:boolean . ''' - tupA = [('http://bsfs.ai/schema/Entity#author', 'Me, myself, and I')] + tupA = [('https://schema.bsfs.io/ie/Node/Entity#author', 'Me, myself, and I')] # constant B csB = ''' bse:rating rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:File ; + rdfs:domain bsn:Entity ; rdfs:range xsd:integer ; bsfs:unique "true"^^xsd:boolean . ''' - tupB = [('http://bsfs.ai/schema/Entity#rating', 123)] + tupB = [('https://schema.bsfs.io/ie/Node/Entity#rating', 123)] # extractors/readers self.ext2rdr = { bsie.extractor.generic.path.Path(): bsie.reader.path.Path(), @@ -49,33 +43,29 @@ class TestPipeline(unittest.TestCase): bsie.extractor.generic.constant.Constant(csA, tupA): None, bsie.extractor.generic.constant.Constant(csB, tupB): None, } - self.prefix = bsfs.Namespace('http://example.com/local/') def test_essentials(self): - pipeline = Pipeline(self.prefix, self.ext2rdr) + pipeline = Pipeline(self.ext2rdr) self.assertEqual(str(pipeline), 'Pipeline') self.assertEqual(repr(pipeline), 'Pipeline(...)') def test_equality(self): - pipeline = Pipeline(self.prefix, self.ext2rdr) + pipeline = Pipeline(self.ext2rdr) # a pipeline is equivalent to itself self.assertEqual(pipeline, pipeline) self.assertEqual(hash(pipeline), hash(pipeline)) # identical builds are equivalent - self.assertEqual(pipeline, Pipeline(self.prefix, self.ext2rdr)) - self.assertEqual(hash(pipeline), hash(Pipeline(self.prefix, self.ext2rdr))) + self.assertEqual(pipeline, Pipeline(self.ext2rdr)) + self.assertEqual(hash(pipeline), hash(Pipeline(self.ext2rdr))) - # equivalence respects prefix - self.assertNotEqual(pipeline, Pipeline(bsfs.URI('http://example.com/global/ent#'), self.ext2rdr)) - self.assertNotEqual(hash(pipeline), hash(Pipeline(bsfs.URI('http://example.com/global/ent#'), self.ext2rdr))) # equivalence respects extractors/readers ext2rdr = {ext: rdr for idx, (ext, rdr) in enumerate(self.ext2rdr.items()) if idx % 2 == 0} - self.assertNotEqual(pipeline, Pipeline(self.prefix, ext2rdr)) - self.assertNotEqual(hash(pipeline), hash(Pipeline(self.prefix, ext2rdr))) + self.assertNotEqual(pipeline, Pipeline(ext2rdr)) + self.assertNotEqual(hash(pipeline), hash(Pipeline(ext2rdr))) # equivalence respects schema - p2 = Pipeline(self.prefix, self.ext2rdr) - p2._schema = pipeline.schema.Empty() + p2 = Pipeline(self.ext2rdr) + p2._schema = bsfs.schema.Schema() self.assertNotEqual(pipeline, p2) self.assertNotEqual(hash(pipeline), hash(p2)) @@ -91,17 +81,17 @@ class TestPipeline(unittest.TestCase): def test_call(self): # build pipeline - pipeline = Pipeline(self.prefix, self.ext2rdr) + pipeline = Pipeline(self.ext2rdr) # build objects for tests content_hash = 'a948904f2f0f479b8f8197694b30184b0d2ed1c1cd2a1ec0fb85d299a192a447' - subject = node.Node(ns.bsfs.File, (self.prefix + 'file#')[content_hash]) + subject = node.Node(ns.bsn.Entity, ucid=content_hash) testfile = os.path.join(os.path.dirname(__file__), 'testfile.t') p_filename = pipeline.schema.predicate(ns.bse.filename) p_filesize = pipeline.schema.predicate(ns.bse.filesize) p_author = pipeline.schema.predicate(ns.bse.author) p_rating = pipeline.schema.predicate(ns.bse.rating) - entity = pipeline.schema.node(ns.bsfs.File) - p_invalid = pipeline.schema.predicate(ns.bsfs.Predicate).get_child(ns.bse.foo, range=entity) + entity = pipeline.schema.node(ns.bsn.Entity) + p_invalid = pipeline.schema.predicate(ns.bsfs.Predicate).child(ns.bse.foo, range=entity) # extract given predicates self.assertSetEqual(set(pipeline(testfile, {p_filename, p_filesize})), { @@ -139,8 +129,8 @@ class TestPipeline(unittest.TestCase): def __call__(self, path): raise errors.ReaderError('reader error') - pipeline = Pipeline(self.prefix, {bsie.extractor.generic.path.Path(): FaultyReader()}) - with self.assertLogs(logging.getLogger('bsie.tools.pipeline'), logging.ERROR): + pipeline = Pipeline({bsie.extractor.generic.path.Path(): FaultyReader()}) + with self.assertLogs(logging.getLogger('bsie.lib.pipeline'), logging.ERROR): testfile = os.path.join(os.path.dirname(__file__), 'testfile.t') p_filename = pipeline.schema.predicate(ns.bse.filename) self.assertSetEqual(set(pipeline(testfile, {p_filename})), set()) @@ -150,15 +140,15 @@ class TestPipeline(unittest.TestCase): def extract(self, subject, content, predicates): raise errors.ExtractorError('extractor error') - pipeline = Pipeline(self.prefix, {FaultyExtractor(): bsie.reader.path.Path()}) - with self.assertLogs(logging.getLogger('bsie.tools.pipeline'), logging.ERROR): + pipeline = Pipeline({FaultyExtractor(): bsie.reader.path.Path()}) + with self.assertLogs(logging.getLogger('bsie.lib.pipeline'), logging.ERROR): testfile = os.path.join(os.path.dirname(__file__), 'testfile.t') p_filename = pipeline.schema.predicate(ns.bse.filename) self.assertSetEqual(set(pipeline(testfile, {p_filename})), set()) def test_predicates(self): # build pipeline - pipeline = Pipeline(self.prefix, self.ext2rdr) + pipeline = Pipeline(self.ext2rdr) # self.assertSetEqual(set(pipeline.principals), { pipeline.schema.predicate(ns.bse.filename), diff --git a/test/tools/__init__.py b/test/reader/image/__init__.py index e69de29..e69de29 100644 --- a/test/tools/__init__.py +++ b/test/reader/image/__init__.py diff --git a/test/reader/image/load_nef.py b/test/reader/image/load_nef.py new file mode 100644 index 0000000..02be470 --- /dev/null +++ b/test/reader/image/load_nef.py @@ -0,0 +1,23 @@ + +# standard imports +import os + +# external imports +import requests + +# constants +IMAGE_URL = 'http://igsor.net/eik7AhvohghaeN5.nef' + +## code ## + +def get(): + """Download a raw test image.""" + target = os.path.join(os.path.dirname(__file__), 'testimage.nef') + if not os.path.exists(target): + with open(target, 'wb') as ofile: + ans = requests.get(IMAGE_URL) + ofile.write(ans.content) + + + +## EOF ## diff --git a/test/reader/image/test_image.py b/test/reader/image/test_image.py new file mode 100644 index 0000000..ee9b8f9 --- /dev/null +++ b/test/reader/image/test_image.py @@ -0,0 +1,49 @@ + +# standard imports +import importlib +import os +import unittest + +# bsie imports +from bsie.utils import errors + +# objects to test +from bsie.reader.image import Image + + +## code ## + +class TestImage(unittest.TestCase): + def setUp(self): + if __package__ is None or __package__ == '': # direct call or local discovery + importlib.import_module('load_nef', __package__).get() + else: # parent discovery + importlib.import_module('.load_nef', __package__).get() + + def test_construct(self): + image = Image({}) + self.assertIsInstance(image, Image) + self.assertEqual(len(image._children), 2) + + def test_call(self): + image = Image({}) + # call returns raw image + img = image(os.path.join(os.path.dirname(__file__), 'testimage.nef')) + self.assertEqual(img.size, (6016, 4016)) # FIXME: change when image was replaced + img.close() + # call returns jpeg image + img = image(os.path.join(os.path.dirname(__file__), 'testimage.jpg')) + self.assertEqual(img.size, (1, 1)) + img.close() + # call raises error if file cannot be read + self.assertRaises(errors.ReaderError, image, + os.path.join(os.path.dirname(__file__), 'invalid.nef')) + self.assertRaises(errors.ReaderError, image, + os.path.join(os.path.dirname(__file__), 'invalid.jpg')) + +## main ## + +if __name__ == '__main__': + unittest.main() + +## EOF ## diff --git a/test/reader/image/test_pillow.py b/test/reader/image/test_pillow.py new file mode 100644 index 0000000..2cff768 --- /dev/null +++ b/test/reader/image/test_pillow.py @@ -0,0 +1,39 @@ + +# standard imports +import os +import unittest + +# external imports +import PIL.Image + +# bsie imports +from bsie.utils import errors + +# objects to test +from bsie.reader.image._pillow import PillowImage + + +## code ## + +class TestPillowImage(unittest.TestCase): + def test_call(self): + rdr = PillowImage() + # returns PIL image + img = rdr(os.path.join(os.path.dirname(__file__), 'testimage.jpg')) + self.assertEqual(img.size, (1, 1)) + self.assertEqual(img.getdata().getpixel((0, 0)), (0, 0, 0)) + img.close() + # raises exception when image cannot be read + self.assertRaises(errors.ReaderError, rdr, + os.path.join(os.path.dirname(__file__), 'invalid.jpg')) + # NOTE: PIL can actually read raw image files (returns the thumbnail) + #self.assertRaises(errors.ReaderError, rdr, + # os.path.join(os.path.dirname(__file__), 'testimage.nef')) + + +## main ## + +if __name__ == '__main__': + unittest.main() + +## EOF ## diff --git a/test/reader/image/test_raw_image.py b/test/reader/image/test_raw_image.py new file mode 100644 index 0000000..3b240d0 --- /dev/null +++ b/test/reader/image/test_raw_image.py @@ -0,0 +1,48 @@ + +# standard imports +import importlib +import os +import unittest + +# external imports +import PIL.Image + +# bsie imports +from bsie.utils import errors + +# objects to test +from bsie.reader.image._raw import RawImage + + +## code ## + +class TestRawImage(unittest.TestCase): + def setUp(self): + if __package__ is None or __package__ == '': # direct call or local discovery + importlib.import_module('load_nef', __package__).get() + else: # parent discovery + importlib.import_module('.load_nef', __package__).get() + + def test_call(self): + rdr = RawImage() + # returns PIL image + img = rdr(os.path.join(os.path.dirname(__file__), 'testimage.nef')) + self.assertEqual(img.size, (6016, 4016)) # FIXME: change when image was replaced + #self.assertEqual(img.size, (1, 1)) + #self.assertEqual(img.getdata().getpixel((0, 0)), (0, 0, 0)) + img.close() + # raises exception when image cannot be read + self.assertRaises(errors.UnsupportedFileFormatError, rdr, + os.path.join(os.path.dirname(__file__), 'testimage.jpg')) + self.assertRaises(errors.ReaderError, rdr, + os.path.join(os.path.dirname(__file__), 'invalid.nef')) + + + + +## main ## + +if __name__ == '__main__': + unittest.main() + +## EOF ## diff --git a/test/reader/image/testimage.jpg b/test/reader/image/testimage.jpg Binary files differnew file mode 100644 index 0000000..ea7af63 --- /dev/null +++ b/test/reader/image/testimage.jpg diff --git a/test/reader/preview/__init__.py b/test/reader/preview/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/reader/preview/__init__.py diff --git a/test/reader/preview/invalid.foo b/test/reader/preview/invalid.foo new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/reader/preview/invalid.foo diff --git a/test/reader/preview/invalid.jpg b/test/reader/preview/invalid.jpg new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/reader/preview/invalid.jpg diff --git a/test/reader/preview/load_nef.py b/test/reader/preview/load_nef.py new file mode 100644 index 0000000..02be470 --- /dev/null +++ b/test/reader/preview/load_nef.py @@ -0,0 +1,23 @@ + +# standard imports +import os + +# external imports +import requests + +# constants +IMAGE_URL = 'http://igsor.net/eik7AhvohghaeN5.nef' + +## code ## + +def get(): + """Download a raw test image.""" + target = os.path.join(os.path.dirname(__file__), 'testimage.nef') + if not os.path.exists(target): + with open(target, 'wb') as ofile: + ans = requests.get(IMAGE_URL) + ofile.write(ans.content) + + + +## EOF ## diff --git a/test/reader/preview/test_pg.py b/test/reader/preview/test_pg.py new file mode 100644 index 0000000..30095c5 --- /dev/null +++ b/test/reader/preview/test_pg.py @@ -0,0 +1,78 @@ + +# standard imports +from functools import partial +import os +import shutil +import tempfile +import unittest + +# external imports +import PIL.Image + +# bsie imports +from bsie.utils import errors + +# objects to test +from bsie.reader.preview._pg import PreviewGeneratorReader + + +## code ## + +class TestPreviewGeneratorReader(unittest.TestCase): + def test_call(self): + rdr = PreviewGeneratorReader() + # inexistent file raises a ReaderError + self.assertRaises(errors.ReaderError, rdr, + os.path.join(os.path.dirname(__file__), 'missing.jpg')) + # unsupported file type raises an UnsupportedFileFormatError + self.assertRaises(errors.UnsupportedFileFormatError, rdr, + os.path.join(os.path.dirname(__file__), 'invalid.foo')) + # invalid file raises a ReaderError + self.assertRaises(errors.ReaderError, + rdr(os.path.join(os.path.dirname(__file__), 'invalid.jpg')), 100) + + # proper file produces a generator + gen = rdr(os.path.join(os.path.dirname(__file__), 'testimage.jpg')) + self.assertIsInstance(gen, partial) + # generator produces an image + img = gen(10) + self.assertIsInstance(img, PIL.Image.Image) + self.assertEqual(img.size, (10, 10)) + self.assertEqual(sum(img.getdata()), 0) + # cleanup + img.close() + + # preview generator can also extract data from non-image files + gen = rdr(os.path.join(os.path.dirname(__file__), 'testfile.pdf')) + self.assertIsInstance(gen, partial) + # generator produces an image + img = gen(10) + self.assertIsInstance(img, PIL.Image.Image) + self.assertEqual(img.size, (8, 10)) + self.assertEqual(sum(img.getdata()), 20258) + # cleanup + img.close() + del rdr + + # can define a cache dir + pg_dir = tempfile.mkdtemp(prefix='bsie-test') + self.assertTrue(os.path.exists(pg_dir)) + rdr = PreviewGeneratorReader(cache=pg_dir) + gen = rdr(os.path.join(os.path.dirname(__file__), 'testimage.jpg')) + img = gen(10) + self.assertIsInstance(img, PIL.Image.Image) + self.assertEqual(img.size, (10, 10)) + self.assertEqual(sum(img.getdata()), 0) + img.close() + del rdr + # cache dir still exists after instance deletion + self.assertTrue(os.path.exists(pg_dir)) + shutil.rmtree(pg_dir, ignore_errors=True) + + +## main ## + +if __name__ == '__main__': + unittest.main() + +## EOF ## diff --git a/test/reader/preview/test_pillow.py b/test/reader/preview/test_pillow.py new file mode 100644 index 0000000..20f08ec --- /dev/null +++ b/test/reader/preview/test_pillow.py @@ -0,0 +1,49 @@ + +# standard imports +from functools import partial +import os +import unittest + +# external imports +import PIL.Image + +# bsie imports +from bsie.utils import errors + +# objects to test +from bsie.reader.preview._pillow import PillowPreviewReader + + +## code ## + +class TestPillowPreviewReader(unittest.TestCase): + def test_call(self): + rdr = PillowPreviewReader() + # raises exception when image cannot be read + self.assertRaises(errors.UnsupportedFileFormatError, rdr, + os.path.join(os.path.dirname(__file__), 'invalid.jpg')) + # raises exception when image cannot be read + self.assertRaises(errors.ReaderError, rdr, + os.path.join(os.path.dirname(__file__), 'inexistent.jpg')) + # raises exception when image has invalid type + self.assertRaises(errors.UnsupportedFileFormatError, rdr, + os.path.join(os.path.dirname(__file__), 'invalid.foo')) + + # proper file produces a generator + gen = rdr(os.path.join(os.path.dirname(__file__), 'testimage.jpg')) + self.assertIsInstance(gen, partial) + # generator produces an image + img = gen(10) + self.assertIsInstance(img, PIL.Image.Image) + self.assertEqual(img.size, (10, 10)) + self.assertEqual(sum(band for pix in img.getdata() for band in pix), 0) + # cleanup + img.close() + + +## main ## + +if __name__ == '__main__': + unittest.main() + +## EOF ## diff --git a/test/reader/preview/test_preview.py b/test/reader/preview/test_preview.py new file mode 100644 index 0000000..e144877 --- /dev/null +++ b/test/reader/preview/test_preview.py @@ -0,0 +1,72 @@ + +# standard imports +from functools import partial +import importlib +import os +import unittest + +# external imports +import PIL.Image + +# bsie imports +from bsie.utils import errors + +# objects to test +from bsie.reader.preview import Preview + + +## code ## + +class TestPreview(unittest.TestCase): + def setUp(self): + if __package__ is None or __package__ == '': # direct call or local discovery + importlib.import_module('load_nef', __package__).get() + else: # parent discovery + importlib.import_module('.load_nef', __package__).get() + + def test_construct(self): + preview = Preview() + self.assertIsInstance(preview, Preview) + self.assertEqual(len(preview._children), 3) + + def test_call(self): + preview = Preview() + # call raises error if file cannot be read + self.assertRaises(errors.ReaderError, preview, + os.path.join(os.path.dirname(__file__), 'missing.jpg')) + self.assertRaises(errors.ReaderError, preview( + os.path.join(os.path.dirname(__file__), 'invalid.jpg')), 10) + self.assertRaises(errors.UnsupportedFileFormatError, preview, + os.path.join(os.path.dirname(__file__), 'invalid.foo')) + + # call returns raw preview + gen = preview(os.path.join(os.path.dirname(__file__), 'testimage.nef')) + img = gen(10) + self.assertIsInstance(img, PIL.Image.Image) + self.assertEqual(img.size, (10, 8)) + self.assertEqual(sum(band for pix in img.getdata() for band in pix), 25287) + img.close() + + # call returns jpeg image + gen = preview(os.path.join(os.path.dirname(__file__), 'testimage.jpg')) + img = gen(10) + self.assertIsInstance(img, PIL.Image.Image) + self.assertEqual(img.size, (10, 10)) + self.assertEqual(sum(band for pix in img.getdata() for band in pix), 0) + img.close() + + # preview generator can also extract data from non-image files + gen = preview(os.path.join(os.path.dirname(__file__), 'testfile.pdf')) + img = gen(10) + self.assertIsInstance(img, PIL.Image.Image) + self.assertEqual(img.size, (8, 10)) + self.assertEqual(sum(img.getdata()), 20258) + img.close() + + +## main ## + +if __name__ == '__main__': + unittest.main() + +## EOF ## diff --git a/test/reader/preview/test_rawpy.py b/test/reader/preview/test_rawpy.py new file mode 100644 index 0000000..11a6f9b --- /dev/null +++ b/test/reader/preview/test_rawpy.py @@ -0,0 +1,54 @@ + +# standard imports +from functools import partial +import importlib +import os +import unittest + +# external imports +import PIL.Image + +# bsie imports +from bsie.utils import errors + +# objects to test +from bsie.reader.preview._rawpy import RawpyPreviewReader + + +## code ## + +class TestRawpyPreviewReader(unittest.TestCase): + def setUp(self): + if __package__ is None or __package__ == '': # direct call or local discovery + importlib.import_module('load_nef', __package__).get() + else: # parent discovery + importlib.import_module('.load_nef', __package__).get() + + def test_call(self): + rdr = RawpyPreviewReader() + # raises exception when image cannot be read + self.assertRaises(errors.ReaderError, rdr, + os.path.join(os.path.dirname(__file__), 'invalid.nef')) + # raises exception when image has invalid type + self.assertRaises(errors.UnsupportedFileFormatError, rdr, + os.path.join(os.path.dirname(__file__), 'invalid.jpg')) + self.assertRaises(errors.UnsupportedFileFormatError, rdr, + os.path.join(os.path.dirname(__file__), 'invalid.foo')) + # proper file produces a generator + gen = rdr(os.path.join(os.path.dirname(__file__), 'testimage.nef')) + self.assertIsInstance(gen, partial) + # generator produces an image + img = gen(10) + self.assertIsInstance(img, PIL.Image.Image) + self.assertEqual(img.size, (10, 7)) + self.assertEqual(sum(band for pix in img.getdata() for band in pix), 15269) + # cleanup + img.close() + + +## main ## + +if __name__ == '__main__': + unittest.main() + +## EOF ## diff --git a/test/reader/preview/test_utils.py b/test/reader/preview/test_utils.py new file mode 100644 index 0000000..2b15bc6 --- /dev/null +++ b/test/reader/preview/test_utils.py @@ -0,0 +1,39 @@ + +# standard imports +import os +import unittest + +# external imports +import PIL.Image + +# objects to test +from bsie.reader.preview.utils import resize + + +## code ## + +class TestUtils(unittest.TestCase): + + def test_resize(self): + img = PIL.Image.open(os.path.join(os.path.dirname(__file__), 'testimage.jpg')) + landscape = img.resize((100, 80)) + portrait = img.resize((80, 100)) + self.assertEqual(img.size, (100, 100)) + self.assertEqual(landscape.size, (100, 80)) + self.assertEqual(portrait.size, (80, 100)) + # resize can downscale + self.assertEqual(resize(img, 10).size, (10, 10)) + self.assertEqual(resize(img, 20).size, (20, 20)) + # resize can upscale + self.assertEqual(resize(img, 200).size, (200, 200)) + # aspect ratio is preserved + self.assertEqual(resize(landscape, 10).size, (10, 8)) + self.assertEqual(resize(portrait, 10).size, (8, 10)) + + +## main ## + +if __name__ == '__main__': + unittest.main() + +## EOF ## diff --git a/test/reader/preview/testfile.pdf b/test/reader/preview/testfile.pdf Binary files differnew file mode 100644 index 0000000..592d448 --- /dev/null +++ b/test/reader/preview/testfile.pdf diff --git a/test/reader/preview/testimage.jpg b/test/reader/preview/testimage.jpg Binary files differnew file mode 100644 index 0000000..4c2aca5 --- /dev/null +++ b/test/reader/preview/testimage.jpg diff --git a/test/base/test_reader.py b/test/reader/test_base.py index a907eb9..5dd2855 100644 --- a/test/base/test_reader.py +++ b/test/reader/test_base.py @@ -1,19 +1,14 @@ -""" -Part of the bsie test suite. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 -""" -# imports +# standard imports import unittest # objects to test -from bsie import base +from bsie.reader import Reader ## code ## -class StubReader(base.Reader): +class StubReader(Reader): def __call__(self, path): raise NotImplementedError() diff --git a/test/reader/test_builder.py b/test/reader/test_builder.py new file mode 100644 index 0000000..84e8e7a --- /dev/null +++ b/test/reader/test_builder.py @@ -0,0 +1,49 @@ + +# standard imports +import unittest + +# bsie imports +from bsie.utils import errors + +# objects to test +from bsie.reader import ReaderBuilder + + +## code ## + +class TestReaderBuilder(unittest.TestCase): + def test_build(self): + builder = ReaderBuilder({'bsie.reader.path.Path': {}}) + # build configured reader + cls = builder.build('bsie.reader.path.Path') + import bsie.reader.path + self.assertIsInstance(cls, bsie.reader.path.Path) + # build unconfigured reader + cls = builder.build('bsie.reader.stat.Stat') + import bsie.reader.stat + self.assertIsInstance(cls, bsie.reader.stat.Stat) + # re-build previous reader (test cache) + self.assertEqual(cls, builder.build('bsie.reader.stat.Stat')) + # test invalid + self.assertRaises(TypeError, builder.build, 123) + self.assertRaises(TypeError, builder.build, None) + self.assertRaises(ValueError, builder.build, '') + self.assertRaises(ValueError, builder.build, 'Path') + self.assertRaises(errors.BuilderError, builder.build, 'path.Path') + # invalid config + builder = ReaderBuilder({'bsie.reader.stat.Stat': dict(foo=123)}) + self.assertRaises(errors.BuilderError, builder.build, 'bsie.reader.stat.Stat') + builder = ReaderBuilder({'bsie.reader.stat.Stat': 123}) + self.assertRaises(TypeError, builder.build, 'bsie.reader.stat.Stat') + # no instructions + builder = ReaderBuilder({}) + cls = builder.build('bsie.reader.stat.Stat') + self.assertIsInstance(cls, bsie.reader.stat.Stat) + + +## main ## + +if __name__ == '__main__': + unittest.main() + +## EOF ## diff --git a/test/reader/test_chain.py b/test/reader/test_chain.py new file mode 100644 index 0000000..665aabc --- /dev/null +++ b/test/reader/test_chain.py @@ -0,0 +1,80 @@ + +# standard imports +import logging +import os +import unittest + +# bsie imports +from bsie.utils import errors +import bsie.reader.path +import bsie.reader.stat + +# objects to test +from bsie.reader.chain import ReaderChain + + +## code ## + +class TestReaderChain(unittest.TestCase): + def test_construct(self): + # subreaders are built + chain = ReaderChain(['bsie.reader.stat.Stat', 'bsie.reader.path.Path'], {}) + self.assertIsInstance(chain, ReaderChain) + self.assertEqual(chain._children, + (bsie.reader.stat.Stat(), bsie.reader.path.Path())) + # subreaders that failed to build are omitted + with self.assertLogs(logging.getLogger('bsie.reader.chain'), logging.WARNING): + chain = ReaderChain(['bsie.reader.stat.Stat', 'bsie.reader.invalid.Invalid'], {}) + self.assertEqual(chain._children, (bsie.reader.stat.Stat(), )) + with self.assertLogs(logging.getLogger('bsie.reader.chain'), logging.WARNING): + chain = ReaderChain(['bsie.reader.stat.Stat', 'bsie.reader.path.Invalid'], {}) + self.assertEqual(chain._children, (bsie.reader.stat.Stat(), )) + # warning is issued if there are no subreaders + with self.assertLogs(logging.getLogger('bsie.reader.chain'), logging.WARNING): + chain = ReaderChain([], {}) + self.assertEqual(chain._children, tuple()) + + def test_essentials(self): + chain = ReaderChain(['bsie.reader.stat.Stat', 'bsie.reader.path.Path'], {}) + # identity + self.assertEqual(chain, chain) + self.assertEqual(hash(chain), hash(chain)) + # comparison works across instances + self.assertEqual(chain, + ReaderChain(['bsie.reader.stat.Stat', 'bsie.reader.path.Path'], {})) + self.assertEqual(hash(chain), + hash(ReaderChain(['bsie.reader.stat.Stat', 'bsie.reader.path.Path'], {}))) + # comparison respects subreaders + self.assertNotEqual(hash(chain), + hash(ReaderChain(['bsie.reader.path.Path'], {}))) + self.assertNotEqual(hash(chain), + hash(ReaderChain(['bsie.reader.path.Path'], {}))) + # comparison respects subreader order + self.assertNotEqual(chain, + ReaderChain(['bsie.reader.path.Path', 'bsie.reader.stat.Stat'], {})) + self.assertNotEqual(hash(chain), + hash(ReaderChain(['bsie.reader.path.Path', 'bsie.reader.stat.Stat'], {}))) + # string representation + self.assertEqual(str(chain), 'ReaderChain(Stat, Path)') + self.assertEqual(repr(chain), 'ReaderChain((Stat(), Path()))') + + def test_call(self): + chain = ReaderChain(['bsie.reader.stat.Stat', 'bsie.reader.path.Path'], {}) + # chain first probes first child + self.assertEqual(chain(__file__), os.stat(__file__)) + # chain probes second child if first one failes + self.assertEqual(chain(''), '') + self.assertEqual(chain('missing-file'), 'missing-file') + + # chain raises a ReaderError if childs were exhausted + chain = ReaderChain(['bsie.reader.stat.Stat'], {}) + # chain probes second child if first one failes + self.assertRaises(errors.ReaderError, chain, '') + + +## main ## + +if __name__ == '__main__': + unittest.main() + +## EOF ## diff --git a/test/reader/test_exif.py b/test/reader/test_exif.py new file mode 100644 index 0000000..de6e801 --- /dev/null +++ b/test/reader/test_exif.py @@ -0,0 +1,52 @@ + +# standard imports +import os +import unittest + +# external imports +import pyexiv2 + +# bsie imports +from bsie.utils import errors + +# objects to test +from bsie.reader.exif import Exif + + +## code ## + +class TestExif(unittest.TestCase): + def test_call(self): + rdr = Exif() + # discards non-image files + self.assertRaises(errors.UnsupportedFileFormatError, rdr, + os.path.join(os.path.dirname(__file__), 'invalid.doc')) + # raises on invalid image files + self.assertRaises(errors.UnsupportedFileFormatError, rdr, + os.path.join(os.path.dirname(__file__), 'invalid.jpg')) + # raises on invalid image files + pyexiv2.set_log_level(3) # suppress log message + self.assertRaises(errors.ReaderError, rdr, + os.path.join(os.path.dirname(__file__), 'testimage_exif_corrupted.jpg')) + # returns dict with exif info + self.assertDictEqual(rdr(os.path.join(os.path.dirname(__file__), 'testimage_exif.jpg')), { + 'Exif.Image.Artist': 'nobody', + 'Exif.Image.ExifTag': '110', + 'Exif.Image.ResolutionUnit': '2', + 'Exif.Image.XResolution': '300/1', + 'Exif.Image.YCbCrPositioning': '1', + 'Exif.Image.YResolution': '300/1', + 'Exif.Photo.ColorSpace': '65535', + 'Exif.Photo.ComponentsConfiguration': '1 2 3 0', + 'Exif.Photo.ExifVersion': '48 50 51 50', + 'Exif.Photo.FlashpixVersion': '48 49 48 48', + 'Exif.Photo.ISOSpeedRatings': '200', + }) + + +## main ## + +if __name__ == '__main__': + unittest.main() + +## EOF ## diff --git a/test/reader/test_path.py b/test/reader/test_path.py index fd7bc5a..f2eee06 100644 --- a/test/reader/test_path.py +++ b/test/reader/test_path.py @@ -1,10 +1,5 @@ -""" -Part of the bsie test suite. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 -""" -# imports +# standard imports import unittest # objects to test diff --git a/test/reader/test_stat.py b/test/reader/test_stat.py index d12ad9c..f36b8b3 100644 --- a/test/reader/test_stat.py +++ b/test/reader/test_stat.py @@ -1,15 +1,10 @@ -""" -Part of the bsie test suite. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 -""" -# imports +# standard imports import os import unittest # bsie imports -from bsie.base import errors +from bsie.utils import errors # objects to test from bsie.reader.stat import Stat diff --git a/test/reader/testimage_exif.jpg b/test/reader/testimage_exif.jpg Binary files differnew file mode 100644 index 0000000..a774bc2 --- /dev/null +++ b/test/reader/testimage_exif.jpg diff --git a/test/reader/testimage_exif_corrupted.jpg b/test/reader/testimage_exif_corrupted.jpg Binary files differnew file mode 100644 index 0000000..e51a9dc --- /dev/null +++ b/test/reader/testimage_exif_corrupted.jpg diff --git a/test/tools/test_builder.py b/test/tools/test_builder.py deleted file mode 100644 index 62c637c..0000000 --- a/test/tools/test_builder.py +++ /dev/null @@ -1,246 +0,0 @@ -""" - -Part of the bsie test suite. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 -""" -# imports -import logging -import unittest - -# bsie imports -from bsie import base -from bsie.utils import bsfs - -# objects to test -from bsie.tools.builder import ExtractorBuilder -from bsie.tools.builder import PipelineBuilder -from bsie.tools.builder import ReaderBuilder -from bsie.tools.builder import _safe_load -from bsie.tools.builder import _unpack_name - - -## code ## - -class TestUtils(unittest.TestCase): - def test_safe_load(self): - # invalid module - self.assertRaises(base.errors.LoaderError, _safe_load, 'dBGHMSAYOoKeKMpywDoKZQycENFPvN', 'foobar') - self.assertRaises(base.errors.LoaderError, _safe_load, 'dBGHMSAYOoKeKMpywDoKZQycENFPvN.bar', 'foobar') - # partially valid module - self.assertRaises(base.errors.LoaderError, _safe_load, 'os.foo', 'foobar') - # invalid class - self.assertRaises(base.errors.LoaderError, _safe_load, 'os.path', 'foo') - # valid module and class - cls = _safe_load('collections.abc', 'Container') - import collections.abc - self.assertEqual(cls, collections.abc.Container) - - def test_unpack_name(self): - self.assertRaises(TypeError, _unpack_name, 123) - self.assertRaises(TypeError, _unpack_name, None) - self.assertRaises(ValueError, _unpack_name, '') - self.assertRaises(ValueError, _unpack_name, 'path') - self.assertRaises(ValueError, _unpack_name, '.Path') - self.assertEqual(_unpack_name('path.Path'), ('path', 'Path')) - self.assertEqual(_unpack_name('path.foo.bar.Path'), ('path.foo.bar', 'Path')) - - -class TestReaderBuilder(unittest.TestCase): - def test_build(self): - builder = ReaderBuilder({'bsie.reader.path.Path': {}}) - # build configured reader - cls = builder.build('bsie.reader.path.Path') - import bsie.reader.path - self.assertIsInstance(cls, bsie.reader.path.Path) - # build unconfigured reader - cls = builder.build('bsie.reader.stat.Stat') - import bsie.reader.stat - self.assertIsInstance(cls, bsie.reader.stat.Stat) - # re-build previous reader (test cache) - self.assertEqual(cls, builder.build('bsie.reader.stat.Stat')) - # test invalid - self.assertRaises(TypeError, builder.build, 123) - self.assertRaises(TypeError, builder.build, None) - self.assertRaises(ValueError, builder.build, '') - self.assertRaises(ValueError, builder.build, 'Path') - self.assertRaises(base.errors.BuilderError, builder.build, 'path.Path') - # invalid config - builder = ReaderBuilder({'bsie.reader.stat.Stat': dict(foo=123)}) - self.assertRaises(base.errors.BuilderError, builder.build, 'bsie.reader.stat.Stat') - builder = ReaderBuilder({'bsie.reader.stat.Stat': 123}) - self.assertRaises(TypeError, builder.build, 'bsie.reader.stat.Stat') - # no instructions - builder = ReaderBuilder({}) - cls = builder.build('bsie.reader.stat.Stat') - self.assertIsInstance(cls, bsie.reader.stat.Stat) - - - -class TestExtractorBuilder(unittest.TestCase): - def test_iter(self): - # no specifications - self.assertListEqual(list(ExtractorBuilder([])), []) - # some specifications - builder = ExtractorBuilder([ - {'bsie.extractor.generic.path.Path': {}}, - {'bsie.extractor.generic.stat.Stat': {}}, - {'bsie.extractor.generic.path.Path': {}}, - ]) - self.assertListEqual(list(builder), [0, 1, 2]) - - def test_build(self): - # simple and repeated extractors - builder = ExtractorBuilder([ - {'bsie.extractor.generic.path.Path': {}}, - {'bsie.extractor.generic.stat.Stat': {}}, - {'bsie.extractor.generic.path.Path': {}}, - ]) - ext = [builder.build(0), builder.build(1), builder.build(2)] - import bsie.extractor.generic.path - import bsie.extractor.generic.stat - self.assertListEqual(ext, [ - bsie.extractor.generic.path.Path(), - bsie.extractor.generic.stat.Stat(), - bsie.extractor.generic.path.Path(), - ]) - # out-of-bounds raises KeyError - self.assertRaises(IndexError, builder.build, 3) - - # building with args - builder = ExtractorBuilder([ - {'bsie.extractor.generic.constant.Constant': { - 'schema': ''' - bse:author rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:Entity ; - rdfs:range xsd:string ; - bsfs:unique "true"^^xsd:boolean . - bse:rating rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:Entity ; - rdfs:range xsd:integer ; - bsfs:unique "true"^^xsd:boolean . - ''', - 'tuples': [ - ('http://bsfs.ai/schema/Entity#author', 'Me, myself, and I'), - ('http://bsfs.ai/schema/Entity#rating', 123), - ], - }}]) - obj = builder.build(0) - import bsie.extractor.generic.constant - self.assertEqual(obj, bsie.extractor.generic.constant.Constant(''' - bse:author rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:Entity ; - rdfs:range xsd:string ; - bsfs:unique "true"^^xsd:boolean . - bse:rating rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:Entity ; - rdfs:range xsd:integer ; - bsfs:unique "true"^^xsd:boolean . - ''', [ - ('http://bsfs.ai/schema/Entity#author', 'Me, myself, and I'), - ('http://bsfs.ai/schema/Entity#rating', 123), - ])) - - # building with invalid args - self.assertRaises(base.errors.BuilderError, ExtractorBuilder( - [{'bsie.extractor.generic.path.Path': {'foo': 123}}]).build, 0) - # non-dict build specification - self.assertRaises(TypeError, ExtractorBuilder( - [('bsie.extractor.generic.path.Path', {})]).build, 0) - # multiple keys per build specification - self.assertRaises(TypeError, ExtractorBuilder( - [{'bsie.extractor.generic.path.Path': {}, - 'bsie.extractor.generic.stat.Stat': {}}]).build, 0) - # non-dict value for kwargs - self.assertRaises(TypeError, ExtractorBuilder( - [{'bsie.extractor.generic.path.Path': 123}]).build, 0) - - - - -class TestPipelineBuilder(unittest.TestCase): - def test_build(self): - prefix = bsfs.URI('http://example.com/local/file#') - c_schema = ''' - bse:author rdfs:subClassOf bsfs:Predicate ; - rdfs:domain bsfs:Entity ; - rdfs:range xsd:string ; - bsfs:unique "true"^^xsd:boolean . - ''' - c_tuples = [('http://bsfs.ai/schema/Entity#author', 'Me, myself, and I')] - # prepare builders - rbuild = ReaderBuilder({}) - ebuild = ExtractorBuilder([ - {'bsie.extractor.generic.path.Path': {}}, - {'bsie.extractor.generic.stat.Stat': {}}, - {'bsie.extractor.generic.constant.Constant': dict( - schema=c_schema, - tuples=c_tuples, - )}, - ]) - # build pipeline - builder = PipelineBuilder(prefix, rbuild, ebuild) - pipeline = builder.build() - # delayed import - import bsie.reader.path - import bsie.reader.stat - import bsie.extractor.generic.path - import bsie.extractor.generic.stat - import bsie.extractor.generic.constant - # check pipeline - self.assertDictEqual(pipeline._ext2rdr, { - bsie.extractor.generic.path.Path(): bsie.reader.path.Path(), - bsie.extractor.generic.stat.Stat(): bsie.reader.stat.Stat(), - bsie.extractor.generic.constant.Constant(c_schema, c_tuples): None, - }) - - # fail to load extractor - ebuild_err = ExtractorBuilder([ - {'bsie.extractor.generic.foo.Foo': {}}, - {'bsie.extractor.generic.path.Path': {}}, - ]) - with self.assertLogs(logging.getLogger('bsie.tools.builder'), logging.ERROR): - pipeline = PipelineBuilder(prefix, rbuild, ebuild_err).build() - self.assertDictEqual(pipeline._ext2rdr, { - bsie.extractor.generic.path.Path(): bsie.reader.path.Path()}) - - # fail to build extractor - ebuild_err = ExtractorBuilder([ - {'bsie.extractor.generic.path.Path': {'foo': 123}}, - {'bsie.extractor.generic.path.Path': {}}, - ]) - with self.assertLogs(logging.getLogger('bsie.tools.builder'), logging.ERROR): - pipeline = PipelineBuilder(prefix, rbuild, ebuild_err).build() - self.assertDictEqual(pipeline._ext2rdr, { - bsie.extractor.generic.path.Path(): bsie.reader.path.Path()}) - - # fail to load reader - with self.assertLogs(logging.getLogger('bsie.tools.builder'), logging.ERROR): - # switch reader of an extractor - old_reader = bsie.extractor.generic.path.Path.CONTENT_READER - bsie.extractor.generic.path.Path.CONTENT_READER = 'bsie.reader.foo.Foo' - # build pipeline with invalid reader reference - pipeline = PipelineBuilder(prefix, rbuild, ebuild).build() - self.assertDictEqual(pipeline._ext2rdr, { - bsie.extractor.generic.stat.Stat(): bsie.reader.stat.Stat(), - bsie.extractor.generic.constant.Constant(c_schema, c_tuples): None, - }) - # switch back - bsie.extractor.generic.path.Path.CONTENT_READER = old_reader - - # fail to build reader - rbuild_err = ReaderBuilder({'bsie.reader.stat.Stat': dict(foo=123)}) - with self.assertLogs(logging.getLogger('bsie.tools.builder'), logging.ERROR): - pipeline = PipelineBuilder(prefix, rbuild_err, ebuild).build() - self.assertDictEqual(pipeline._ext2rdr, { - bsie.extractor.generic.path.Path(): bsie.reader.path.Path(), - bsie.extractor.generic.constant.Constant(c_schema, c_tuples): None, - }) - - -## main ## - -if __name__ == '__main__': - unittest.main() - -## EOF ## diff --git a/test/tools/testfile.t b/test/tools/testfile.t deleted file mode 100644 index 3b18e51..0000000 --- a/test/tools/testfile.t +++ /dev/null @@ -1 +0,0 @@ -hello world diff --git a/test/utils/filematcher/__init__.py b/test/utils/filematcher/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/utils/filematcher/__init__.py diff --git a/test/utils/filematcher/empty b/test/utils/filematcher/empty new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test/utils/filematcher/empty diff --git a/test/utils/filematcher/test_matcher.py b/test/utils/filematcher/test_matcher.py new file mode 100644 index 0000000..88e96c2 --- /dev/null +++ b/test/utils/filematcher/test_matcher.py @@ -0,0 +1,227 @@ + +# standard imports +import os +import stat +import tempfile +import unittest + +# objects to test +from bsie.utils.filematcher import matcher + + +## code ## + +class FakeMatcher(matcher.Matcher): + def __call__(self, *args, **kwargs): + pass + +class FakeCriterion(matcher.Criterion): + def __call__(self, *args, **kwargs): + pass + +class FakeAggregate(matcher.Aggregate): + def __call__(self, *args, **kwargs): + pass + +class TestMatcher(unittest.TestCase): + def setUp(self): + # paths + self.image = os.path.join(os.path.dirname(__file__), 'testimage.jpg') + self.text= os.path.join(os.path.dirname(__file__), 'textfile.t') + self.empty = os.path.join(os.path.dirname(__file__), 'empty') + self.missing = os.path.join(os.path.dirname(__file__), 'missing.jpg') + + def test_matcher_skeleton(self): + # node: iteration and length + self.assertSetEqual(set(iter(FakeMatcher(1,2,3))), {1,2,3}) + self.assertSetEqual(set(iter(FakeMatcher([1,2,3]))), {1,2,3}) + self.assertEqual(len(FakeMatcher([1,2,3])), 3) + self.assertEqual(len(FakeMatcher(1,2,3)), 3) + self.assertEqual(len(FakeMatcher()), 0) + self.assertIn(1, FakeMatcher(1,2,3)) + self.assertIn(3, FakeMatcher([1,2,3])) + self.assertNotIn(0, FakeMatcher(1,2,3)) + self.assertNotIn(4, FakeMatcher([1,2,3])) + # node: comparison + self.assertEqual(FakeMatcher([1,2,3]), FakeMatcher([1,2,3])) + self.assertEqual(FakeMatcher(1,2,3), FakeMatcher(1,2,3)) + self.assertEqual(FakeMatcher(1,2,3), FakeMatcher([1,2,3])) + self.assertEqual(FakeMatcher(1,2,3), FakeMatcher((1,2,3))) + self.assertNotEqual(FakeMatcher(1,2,3), FakeMatcher(1,2,4)) + self.assertNotEqual(FakeMatcher(1,2,3), FakeMatcher(1,2,3,4)) + self.assertNotEqual(FakeMatcher(1,2,3), FakeMatcher(1,2)) + self.assertEqual(hash(FakeMatcher([1,2,3])), hash(FakeMatcher([1,2,3]))) + self.assertEqual(hash(FakeMatcher(1,2,3)), hash(FakeMatcher(1,2,3))) + self.assertEqual(hash(FakeMatcher(1,2,3)), hash(FakeMatcher([1,2,3]))) + self.assertEqual(hash(FakeMatcher(1,2,3)), hash(FakeMatcher((1,2,3)))) + # node: representation + self.assertEqual(repr(FakeMatcher(1,2,3)), 'FakeMatcher({1, 2, 3})') + + # criterion + self.assertEqual(repr(FakeCriterion(1,2,3)), 'FakeCriterion({1, 2, 3})') + self.assertEqual(hash(FakeCriterion(1,2,3)), hash(FakeCriterion(1,2,3))) + self.assertEqual(FakeCriterion(1,2,3), FakeCriterion([1,2,3])) + self.assertNotEqual(FakeCriterion(1,2,3), FakeCriterion(1,2)) + self.assertNotEqual(FakeCriterion(1,2,3), FakeMatcher(1,2,3)) + self.assertSetEqual(FakeCriterion(1,2,3).accepted(), {1,2,3}) + + # aggregate + self.assertEqual(repr(FakeAggregate(1,2,3)), 'FakeAggregate({1, 2, 3})') + self.assertNotEqual(FakeAggregate(1,2,3), FakeMatcher(1,2,3)) + + def test_any(self): + self.assertTrue(matcher.Any()(self.image)) + self.assertTrue(matcher.Any()(self.text)) + self.assertTrue(matcher.Any()(self.missing)) + self.assertTrue(matcher.Any()(self.empty)) + + def test_nothing(self): + self.assertFalse(matcher.Nothing()(self.image)) + self.assertFalse(matcher.Nothing()(self.text)) + self.assertFalse(matcher.Nothing()(self.missing)) + self.assertFalse(matcher.Nothing()(self.empty)) + + def test_exists(self): + self.assertTrue(matcher.Exists()(self.image)) + self.assertTrue(matcher.Exists()(self.text)) + self.assertTrue(matcher.Exists()(self.empty)) + self.assertFalse(matcher.Exists()(self.missing)) + + def test_isfile(self): + self.assertTrue(matcher.IsFile()(self.image)) + self.assertTrue(matcher.IsFile()(self.text)) + self.assertFalse(matcher.IsFile()(self.missing)) + self.assertFalse(matcher.IsFile()(os.path.dirname(self.image))) + + def test_isdir(self): + self.assertTrue(matcher.IsDir()(os.path.dirname(self.image))) + self.assertFalse(matcher.IsDir()(self.image)) + self.assertFalse(matcher.IsDir()(self.text)) + self.assertFalse(matcher.IsDir()(self.missing)) + + def test_islink(self): + self.assertFalse(matcher.IsLink()(os.path.dirname(self.image))) + self.assertFalse(matcher.IsLink()(self.image)) + self.assertFalse(matcher.IsLink()(self.text)) + _, temp = tempfile.mkstemp(prefix='bsie-test-') + templink = temp + '-link' + os.symlink(temp, templink) + self.assertTrue(matcher.IsLink()(templink)) + os.unlink(templink) + os.unlink(temp) + + def test_isabs(self): + self.assertTrue(matcher.IsAbs()(os.path.abspath(self.image))) + self.assertTrue(matcher.IsAbs()(os.path.abspath(self.text))) + self.assertFalse(matcher.IsAbs()(os.path.relpath(self.text, os.path.dirname(self.text)))) + + def test_isrel(self): + self.assertFalse(matcher.IsRel()(os.path.abspath(self.image))) + self.assertFalse(matcher.IsRel()(os.path.abspath(self.text))) + self.assertTrue(matcher.IsRel()(os.path.relpath(self.text, os.path.dirname(self.text)))) + self.assertTrue(matcher.IsRel()(os.path.basename(self.text))) + + def test_ismount(self): + self.assertFalse(matcher.IsMount()(self.image)) + self.assertFalse(matcher.IsMount()(self.text)) + self.assertFalse(matcher.IsMount()(self.missing)) + # there's no reasonable way to test a positive case + + def test_isempty(self): + self.assertTrue(matcher.IsEmpty()(self.empty)) + self.assertFalse(matcher.IsEmpty()(self.image)) + self.assertFalse(matcher.IsEmpty()(self.text)) + self.assertFalse(matcher.IsEmpty()(self.missing)) + + def test_isreadable(self): + self.assertTrue(matcher.IsReadable()(self.empty)) + self.assertTrue(matcher.IsReadable()(self.image)) + self.assertFalse(matcher.IsReadable()(self.missing)) + _, temp = tempfile.mkstemp(prefix='bsie-test-') + os.chmod(temp, 0) + self.assertFalse(matcher.IsReadable()(temp)) + os.unlink(temp) + + def test_iswritable(self): + self.assertTrue(matcher.IsWritable()(self.empty)) + self.assertTrue(matcher.IsWritable()(self.image)) + self.assertFalse(matcher.IsWritable()(self.missing)) + _, temp = tempfile.mkstemp(prefix='bsie-test-') + os.chmod(temp, 0) + self.assertFalse(matcher.IsWritable()(temp)) + os.unlink(temp) + + def test_isexecutable(self): + self.assertFalse(matcher.IsExecutable()(self.empty)) + self.assertFalse(matcher.IsExecutable()(self.image)) + self.assertFalse(matcher.IsExecutable()(self.missing)) + _, temp = tempfile.mkstemp(prefix='bsie-test-') + os.chmod(temp, stat.S_IEXEC) + self.assertTrue(matcher.IsExecutable()(temp)) + os.unlink(temp) + + def test_extension(self): + self.assertTrue(matcher.Extension('jpg')(self.image)) + self.assertTrue(matcher.Extension('jpg', 'png')(self.image)) + self.assertTrue(matcher.Extension('jpg', 't')(self.text)) + self.assertTrue(matcher.Extension('jpg', 'png', 't')(self.missing)) + self.assertTrue(matcher.Extension('')(self.empty)) + + self.assertFalse(matcher.Extension()(self.image)) + self.assertFalse(matcher.Extension('jpeg')(self.image)) + self.assertFalse(matcher.Extension('.t')(self.text)) + self.assertFalse(matcher.Extension('png', 't')(self.missing)) + self.assertFalse(matcher.Extension('tiff')(self.empty)) + + def test_mime(self): + self.assertTrue(matcher.Mime('image/jpeg')(self.image)) + self.assertTrue(matcher.Mime('image/tiff', 'image/jpeg')(self.image)) + self.assertTrue(matcher.Mime('text/plain', 'image/jpeg')(self.text)) + self.assertTrue(matcher.Mime('inode/x-empty')(self.empty)) + + self.assertFalse(matcher.Mime()(self.image)) + self.assertFalse(matcher.Mime('image')(self.image)) + self.assertFalse(matcher.Mime('image/tiff', 'image/png')(self.image)) + self.assertFalse(matcher.Mime('')(self.text)) + self.assertFalse(matcher.Mime('text')(self.text)) + self.assertFalse(matcher.Mime('tiff')(self.empty)) + self.assertFalse(matcher.Mime()(self.empty)) + self.assertFalse(matcher.Mime('')(self.empty)) + self.assertFalse(matcher.Mime()(self.missing)) + self.assertFalse(matcher.Mime('')(self.missing)) + self.assertFalse(matcher.Mime('inode/x-empty')(self.missing)) + + def test_not(self): + self.assertFalse(matcher.NOT(matcher.Mime('image/jpeg'))(self.image)) + self.assertTrue(matcher.NOT(matcher.Mime('text/plain'))(self.image)) + + def test_and(self): + self.assertTrue(matcher.And(matcher.Mime('image/jpeg'), matcher.Extension('jpg'))(self.image)) + self.assertTrue(matcher.And(matcher.Mime('image/jpeg'), matcher.Extension('jpg', 'tiff'))(self.image)) + self.assertTrue(matcher.And(matcher.Mime('text/plain'), matcher.Extension('t', 'tiff'))(self.text)) + + self.assertFalse(matcher.And(matcher.Mime('image/jpeg'), matcher.Extension('tiff'))(self.image)) + self.assertFalse(matcher.And(matcher.Mime('text/plain'), matcher.Extension('jpg'))(self.image)) + self.assertFalse(matcher.And(matcher.Mime('inode/x-empty'), matcher.Extension('jpg'))(self.missing)) + self.assertFalse(matcher.And(matcher.Mime('image/jpeg'), matcher.Extension('jpg', 't'))(self.text)) + + def test_or(self): + self.assertTrue(matcher.Or(matcher.Mime('image/jpeg'))(self.image)) + self.assertFalse(matcher.Or(matcher.Mime('text/plain'))(self.image)) + + self.assertTrue(matcher.Or(matcher.Mime('image/jpeg'), matcher.Extension('jpg'))(self.image)) + self.assertTrue(matcher.Or(matcher.Mime('image/jpeg'), matcher.Extension('t'))(self.image)) + self.assertTrue(matcher.Or(matcher.Mime('text/plain'), matcher.Extension('jpg', 'tiff'))(self.image)) + self.assertTrue(matcher.Or(matcher.Mime('text/plain'), matcher.Extension('tiff'))(self.text)) + self.assertTrue(matcher.Or(matcher.Mime('image/jpeg'), matcher.Extension('jpg'))(self.missing)) + + self.assertFalse(matcher.Or(matcher.Mime('text/plain'), matcher.Extension('tiff'))(self.image)) + self.assertFalse(matcher.Or(matcher.Mime('inode/x-empty'), matcher.Extension('jpg', 'tiff'))(self.text)) + + +## main ## + +if __name__ == '__main__': + unittest.main() + +## EOF ## diff --git a/test/utils/filematcher/test_parser.py b/test/utils/filematcher/test_parser.py new file mode 100644 index 0000000..536db00 --- /dev/null +++ b/test/utils/filematcher/test_parser.py @@ -0,0 +1,141 @@ + +# standard imports +import unittest + +# bsie imports +from bsie.utils import errors +from bsie.utils.filematcher import matcher + +# objects to test +from bsie.utils.filematcher import parse + + +## code ## + +class TestFileMatcherParser(unittest.TestCase): + def test_empty(self): + # no criterion + self.assertEqual(parse(''), matcher.Any()) + + def test_ruleone(self): + # single criterion, single value + self.assertEqual(parse('mime=text'), matcher.Mime('text')) + self.assertEqual(parse('MIME=text'), matcher.Mime('text')) + self.assertEqual(parse('MiMe=text'), matcher.Mime('text')) + self.assertEqual(parse('MIME=TEXT'), matcher.Mime('TEXT')) + self.assertEqual(parse('mime={text}'), matcher.Mime('text')) + self.assertEqual(parse('mime=image/jpeg'), matcher.Mime('image/jpeg')) + self.assertEqual(parse('mime="image/jpeg"'), matcher.Mime('image/jpeg')) + self.assertEqual(parse('extension=pdf'), matcher.Extension('pdf')) + self.assertEqual(parse('extension={pdf}'), matcher.Extension('pdf')) + self.assertEqual(parse('extension="pdf"'), matcher.Extension('pdf')) + self.assertEqual(parse('extension="foo,bar"'), matcher.Extension('foo,bar')) + self.assertEqual(parse('extension="f{oo|ba}r"'), matcher.Extension('f{oo|ba}r')) + self.assertEqual(parse('extension=""'), matcher.Extension('')) + self.assertEqual(parse('extension="foo'), matcher.Extension('"foo')) + self.assertRaises(errors.ParserError, parse, 'extension=foo=bar') + self.assertRaises(errors.ParserError, parse, 'extension=') + self.assertRaises(errors.ParserError, parse, 'extension={}') + self.assertRaises(errors.ParserError, parse, 'extension={foo') + + # valueless + self.assertEqual(parse('any'), matcher.Any()) + self.assertEqual(parse('nothing'), matcher.Nothing()) + self.assertEqual(parse('exists'), matcher.Exists()) + self.assertEqual(parse('any, nothing'), matcher.And(matcher.Any(), matcher.Nothing())) + self.assertEqual(parse('any, nothing, exists'), + matcher.And(matcher.Any(), matcher.Nothing(), matcher.Exists())) + self.assertEqual(parse('any, extension=jpg'), matcher.And(matcher.Any(), matcher.Extension('jpg'))) + self.assertRaises(errors.ParserError, parse, 'mime') + self.assertRaises(errors.ParserError, parse, 'extension') + self.assertRaises(errors.ParserError, parse, 'exists=True') + self.assertRaises(errors.ParserError, parse, 'exists=foo') + self.assertEqual(parse('!any'), matcher.NOT(matcher.Any())) + self.assertEqual(parse('!any, nothing'), matcher.And(matcher.NOT(matcher.Any()), matcher.Nothing())) + self.assertEqual(parse('!any, extension=jpg'), + matcher.And(matcher.NOT(matcher.Any()), matcher.Extension('jpg'))) + self.assertRaises(errors.ParserError, parse, '!mime') + self.assertRaises(errors.ParserError, parse, '!extension') + + def test_rulefew(self): + # single criterion, multiple values + self.assertEqual(parse('extension={jpg, jpeg}'), matcher.Extension('jpg', 'jpeg')) + self.assertEqual(parse('mime={image/jpeg, image/png}'), + matcher.Mime('image/jpeg', 'image/png')) + self.assertRaises(errors.ParserError, parse, 'mime=image/png, image/jpeg') + self.assertRaises(errors.ParserError, parse, 'extension=jpg, jpeg') + + def test_rulesets_ruleone(self): + # mutliple criteria, single value + self.assertEqual(parse('mime=text, extension=t'), + matcher.And(matcher.Mime('text'), matcher.Extension('t'))) + self.assertEqual(parse('mime=text/plain, extension=t'), + matcher.And(matcher.Mime('text/plain'), matcher.Extension('t'))) + self.assertRaises(errors.ParserError, parse, 'mime=text/plain extension=t') + self.assertRaises(errors.ParserError, parse, 'mime={image/jpeg, extension=jpg'), + + def test_rulesets_rulefew(self): + # multiple criteria, multiple values + self.assertEqual(parse('mime=image/jpeg, extension={jpg, jpeg}'), + matcher.And(matcher.Mime('image/jpeg'), matcher.Extension('jpg', 'jpeg'))) + self.assertEqual(parse('mime={image/jpeg, image/tiff}, extension={jpg, jpeg}'), + matcher.And(matcher.Mime('image/jpeg', 'image/tiff'), matcher.Extension('jpg', 'jpeg'))) + self.assertEqual(parse('mime={image/jpeg, image/tiff}, extension=jpg'), + matcher.And(matcher.Mime('image/jpeg', 'image/tiff'), matcher.Extension('jpg'))) + self.assertRaises(errors.ParserError, parse, 'mime={image/jpeg, image/tiff, extension=jpg') + self.assertRaises(errors.ParserError, parse, 'mime=image/jpeg, image/tiff, extension=jpg') + self.assertRaises(errors.ParserError, parse, 'mime=image/jpeg, extension=jpg, ') + + def test_not(self): + self.assertEqual(parse('extension!=jpg'), matcher.NOT(matcher.Extension('jpg'))) + self.assertEqual(parse('extension!={jpg, jpeg}'), + matcher.NOT(matcher.Extension('jpg', 'jpeg'))) + self.assertEqual(parse('extension!=jpg, mime=image/jpeg'), + matcher.And(matcher.NOT(matcher.Extension('jpg')), matcher.Mime('image/jpeg'))) + self.assertEqual(parse('extension!=jpg, mime!=image/jpeg'), + matcher.And(matcher.NOT(matcher.Extension('jpg')), matcher.NOT(matcher.Mime('image/jpeg')))) + self.assertEqual(parse('extension!=jpg | mime=image/jpeg'), + matcher.Or(matcher.NOT(matcher.Extension('jpg')), matcher.Mime('image/jpeg'))) + self.assertEqual(parse('extension!=jpg | mime!=image/jpeg'), + matcher.Or(matcher.NOT(matcher.Extension('jpg')), matcher.NOT(matcher.Mime('image/jpeg')))) + + def test_expr(self): + # multiple rulesets + self.assertEqual(parse('mime=image/jpeg | extension=jpg'), + matcher.Or(matcher.Mime('image/jpeg'), matcher.Extension('jpg'))) + self.assertEqual(parse('mime=image/jpeg | extension={jpg, jpeg}'), + matcher.Or(matcher.Mime('image/jpeg'), matcher.Extension('jpg', 'jpeg'))) + self.assertEqual(parse('mime={image/jpeg, image/png} | extension={jpg, jpeg}'), + matcher.Or(matcher.Mime('image/jpeg', 'image/png'), matcher.Extension('jpg', 'jpeg'))) + self.assertEqual(parse('mime=image/jpeg , extension=jpg | extension=jpg'), + matcher.Or(matcher.And(matcher.Mime('image/jpeg'), matcher.Extension('jpg')), matcher.Extension('jpg'))) + self.assertEqual(parse( + 'mime={jpeg, text}, extension={jpg,t} | extension={png,txt}, mime={png, tiff}'), + matcher.Or( + matcher.And(matcher.Mime('jpeg', 'text'), matcher.Extension('jpg', 't')), + matcher.And(matcher.Extension('png', 'txt'), matcher.Mime('png', 'tiff')))) + self.assertEqual(parse('mime=text | extension=jpg | extension=png | mime=png'), + matcher.Or(matcher.Mime('text'), matcher.Extension('jpg'), matcher.Extension('png'), matcher.Mime('png'))) + self.assertRaises(errors.ParserError, parse, 'mime=text |') + self.assertRaises(errors.ParserError, parse, '| mime=text') + self.assertRaises(errors.ParserError, parse, 'extension=png | mime=text, ') + + def test_invalid(self): + # Invalid parses + self.assertRaises(errors.ParserError, parse, "extension=") # Empty value + self.assertRaises(errors.ParserError, parse, "mime=foo,bar") # Escaping + self.assertRaises(errors.ParserError, parse, "mime='foo,bar") # Quoting + self.assertRaises(errors.ParserError, parse, "mime=\"foo,bar") # Quoting + + # Invalid input + self.assertRaises(AttributeError, parse, None) + self.assertRaises(AttributeError, parse, 123) + self.assertRaises(AttributeError, parse, [123,321]) + + +## main ## + +if __name__ == '__main__': + unittest.main() + +## EOF ## diff --git a/test/utils/filematcher/testimage.jpg b/test/utils/filematcher/testimage.jpg Binary files differnew file mode 100644 index 0000000..ea7af63 --- /dev/null +++ b/test/utils/filematcher/testimage.jpg diff --git a/test/utils/filematcher/textfile.t b/test/utils/filematcher/textfile.t new file mode 100644 index 0000000..c389011 --- /dev/null +++ b/test/utils/filematcher/textfile.t @@ -0,0 +1,4 @@ +Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. +Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. +Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. +Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. diff --git a/test/utils/test_loading.py b/test/utils/test_loading.py new file mode 100644 index 0000000..b8773ab --- /dev/null +++ b/test/utils/test_loading.py @@ -0,0 +1,43 @@ + +# standard imports +import unittest + +# bsie imports +from bsie.utils import errors + +# objects to test +from bsie.utils.loading import safe_load, unpack_qualified_name + + +## code ## + +class TestUtils(unittest.TestCase): + def test_safe_load(self): + # invalid module + self.assertRaises(errors.LoaderError, safe_load, 'dBGHMSAYOoKeKMpywDoKZQycENFPvN', 'foobar') + self.assertRaises(errors.LoaderError, safe_load, 'dBGHMSAYOoKeKMpywDoKZQycENFPvN.bar', 'foobar') + # partially valid module + self.assertRaises(errors.LoaderError, safe_load, 'os.foo', 'foobar') + # invalid class + self.assertRaises(errors.LoaderError, safe_load, 'os.path', 'foo') + # valid module and class + cls = safe_load('collections.abc', 'Container') + import collections.abc + self.assertEqual(cls, collections.abc.Container) + + def test_unpack_qualified_name(self): + self.assertRaises(TypeError, unpack_qualified_name, 123) + self.assertRaises(TypeError, unpack_qualified_name, None) + self.assertRaises(ValueError, unpack_qualified_name, '') + self.assertRaises(ValueError, unpack_qualified_name, 'path') + self.assertRaises(ValueError, unpack_qualified_name, '.Path') + self.assertEqual(unpack_qualified_name('path.Path'), ('path', 'Path')) + self.assertEqual(unpack_qualified_name('path.foo.bar.Path'), ('path.foo.bar', 'Path')) + + +## main ## + +if __name__ == '__main__': + unittest.main() + +## EOF ## diff --git a/test/utils/test_node.py b/test/utils/test_node.py index c70f0b8..c0662a1 100644 --- a/test/utils/test_node.py +++ b/test/utils/test_node.py @@ -1,10 +1,5 @@ -""" -Part of the bsie test suite. -A copy of the license is provided with the project. -Author: Matthias Baumgartner, 2022 -""" -# imports +# standard imports import unittest # bsie imports @@ -18,22 +13,54 @@ from bsie.utils.node import Node class TestNode(unittest.TestCase): def test_equality(self): - uri = bsfs.URI('http://example.com/me/entity#1234') - node = Node(ns.bsfs.Entity, uri) - # basic equivalence - self.assertEqual(node, Node(ns.bsfs.Entity, bsfs.URI('http://example.com/me/entity#1234'))) - self.assertEqual(hash(node), hash(Node(ns.bsfs.Entity, bsfs.URI('http://example.com/me/entity#1234')))) + uri1 = bsfs.URI('http://example.com/me/entity#1234') + uri2 = bsfs.URI('http://example.com/me/entity#4321') + node = Node(ns.bsfs.Entity, uri1) # equality respects uri - self.assertNotEqual(node, Node(ns.bsfs.Entity, bsfs.URI('http://example.com/me/entity#4321'))) - self.assertNotEqual(hash(node), hash(Node(ns.bsfs.Entity, bsfs.URI('http://example.com/me/entity#4321')))) + self.assertEqual(node, Node(ns.bsfs.Entity, uri1)) + self.assertEqual(hash(node), hash(Node(ns.bsfs.Entity, uri1))) + self.assertNotEqual(node, Node(ns.bsfs.Entity, uri2)) + self.assertNotEqual(hash(node), hash(Node(ns.bsfs.Entity, uri2))) + # equality respects hints + self.assertEqual( + Node(ns.bsfs.Entity, foo='foo'), + Node(ns.bsfs.Entity, foo='foo')) + self.assertEqual( + hash(Node(ns.bsfs.Entity, foo='foo')), + hash(Node(ns.bsfs.Entity, foo='foo'))) + self.assertNotEqual( + Node(ns.bsfs.Entity, foo='foo'), + Node(ns.bsfs.Entity, foo='bar')) + self.assertNotEqual( + hash(Node(ns.bsfs.Entity, foo='foo')), + hash(Node(ns.bsfs.Entity, foo='bar'))) + self.assertNotEqual( + Node(ns.bsfs.Entity, foo='bar'), + Node(ns.bsfs.Entity, bar='foo')) + self.assertNotEqual( + hash(Node(ns.bsfs.Entity, foo='bar')), + hash(Node(ns.bsfs.Entity, bar='foo'))) + # hints are irrelevant if uri is set + self.assertEqual( + Node(ns.bsfs.Entity, uri=uri1, foo='bar'), + Node(ns.bsfs.Entity, uri=uri1, bar='foo')) + self.assertEqual( + hash(Node(ns.bsfs.Entity, uri=uri1, foo='bar')), + hash(Node(ns.bsfs.Entity, uri=uri1, bar='foo'))) + self.assertNotEqual( + Node(ns.bsfs.Entity, uri=uri1, foo='bar'), + Node(ns.bsfs.Entity, uri=uri2, bar='foo')) + self.assertNotEqual( + hash(Node(ns.bsfs.Entity, uri=uri1, foo='bar')), + hash(Node(ns.bsfs.Entity, uri=uri2, bar='foo'))) # equality respects node_type - self.assertNotEqual(node, Node(ns.bsfs.Foo, uri)) - self.assertNotEqual(hash(node), hash(Node(ns.bsfs.Foo, uri))) + self.assertNotEqual(node, Node(ns.bsfs.Foo, uri1)) + self.assertNotEqual(hash(node), hash(Node(ns.bsfs.Foo, uri1))) # not equal to other types self.assertNotEqual(node, 1234) self.assertNotEqual(hash(node), hash(1234)) - self.assertNotEqual(node, uri) - self.assertNotEqual(hash(node), hash(uri)) + self.assertNotEqual(node, uri1) + self.assertNotEqual(hash(node), hash(uri1)) self.assertNotEqual(node, ns.bsfs.Entity) self.assertNotEqual(hash(node), hash(ns.bsfs.Entity)) class Foo(): pass @@ -43,17 +70,17 @@ class TestNode(unittest.TestCase): def test_str(self): uri = bsfs.URI('http://example.com/me/entity#1234') # basic string conversion - node = Node(ns.bsfs.Entity, uri) - self.assertEqual(str(node), 'Node(http://bsfs.ai/schema/Entity, http://example.com/me/entity#1234)') - self.assertEqual(repr(node), 'Node(http://bsfs.ai/schema/Entity, http://example.com/me/entity#1234)') + node = Node(ns.bsn.Entity, uri) + self.assertEqual(str(node), 'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/entity#1234)') + self.assertEqual(repr(node), 'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/entity#1234)') # string conversion respects node_type - node = Node(ns.bsfs.Foo, uri) - self.assertEqual(str(node), 'Node(http://bsfs.ai/schema/Foo, http://example.com/me/entity#1234)') - self.assertEqual(repr(node), 'Node(http://bsfs.ai/schema/Foo, http://example.com/me/entity#1234)') + node = Node(ns.bsn.Foo, uri) + self.assertEqual(str(node), 'Node(https://schema.bsfs.io/ie/Node/Foo, http://example.com/me/entity#1234)') + self.assertEqual(repr(node), 'Node(https://schema.bsfs.io/ie/Node/Foo, http://example.com/me/entity#1234)') # string conversion respects uri - node = Node(ns.bsfs.Entity, bsfs.URI('http://example.com/me/entity#4321')) - self.assertEqual(str(node), 'Node(http://bsfs.ai/schema/Entity, http://example.com/me/entity#4321)') - self.assertEqual(repr(node), 'Node(http://bsfs.ai/schema/Entity, http://example.com/me/entity#4321)') + node = Node(ns.bsn.Entity, bsfs.URI('http://example.com/me/entity#4321')) + self.assertEqual(str(node), 'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/entity#4321)') + self.assertEqual(repr(node), 'Node(https://schema.bsfs.io/ie/Node/Entity, http://example.com/me/entity#4321)') |