import logging import os.path import shutil import tempfile import unittest import git import ruamel.yaml import lesana class testCollection(unittest.TestCase): def tearDown(self): shutil.rmtree(os.path.join(self.collection.basedir, '.lesana')) def test_empty(self): self.collection = lesana.Collection('tests/data/empty') self.assertEqual(self.collection.settings, {}) self.collection.update_cache() self.assertIsNotNone(self.collection.stemmer) def test_load_simple(self): self.collection = lesana.Collection('tests/data/simple') self.assertIsNotNone(self.collection.settings) self.assertEqual( self.collection.settings['name'], "Simple lesana collection" ) self.assertEqual(len(self.collection.settings['fields']), 7) self.assertEqual(len(self.collection.indexed_fields), 3) self.collection.update_cache() self.assertIsNotNone(self.collection.stemmer) def test_load_wrong_language(self): # This loads a collection with an invalid value in lang with self.assertLogs(level=logging.WARNING) as cm: self.collection = lesana.Collection('tests/data/wrong') self.assertEqual(len(cm.output), 1) self.assertIn("Invalid language", cm.output[0]) # The collection will default to english, but should still work. self.collection.update_cache() self.assertIsNotNone(self.collection.settings) self.assertIsNotNone(self.collection.stemmer) def test_load_no_index_for_one_entry(self): # This loads a collection where some of the entries have no # "index" field with self.assertLogs(level=logging.WARNING): self.collection = lesana.Collection('tests/data/wrong') self.collection.update_cache() self.assertIsNotNone(self.collection.settings) self.assertIsNotNone(self.collection.stemmer) # Fields with no "index" entry are not indexed self.assertEqual(len(self.collection.settings['fields']), 7) self.assertEqual(len(self.collection.indexed_fields), 3) def test_load_safe(self): self.collection = lesana.Collection('tests/data/simple') self.collection.safe = True self.collection.update_cache() def test_full_search(self): self.collection = lesana.Collection('tests/data/simple') self.collection.start_search('Item') res = self.collection.get_all_search_results() matches = list(res) self.assertEqual(len(matches), 2) for m in matches: self.assertIsInstance(m, lesana.Entry) def test_search(self): self.collection = lesana.Collection('tests/data/simple') self.collection.start_search('Item') res = self.collection.get_search_results() matches = list(res) self.assertEqual(len(matches), 2) for m in matches: self.assertIsInstance(m, lesana.Entry) def test_search_wildcard(self): self.collection = lesana.Collection('tests/data/simple') self.collection.start_search('Ite*') res = self.collection.get_search_results() matches = list(res) self.assertEqual(len(matches), 2) for m in matches: self.assertIsInstance(m, lesana.Entry) def test_search_non_init(self): self.collection = lesana.Collection('tests/data/simple') matches = list(self.collection.get_search_results()) self.assertEqual(matches, []) matches = list(self.collection.get_all_search_results()) self.assertEqual(matches, []) def test_all_entries(self): self.collection = lesana.Collection('tests/data/simple') res = self.collection.get_all_documents() matches = list(res) self.assertEqual(len(matches), 3) for m in matches: self.assertIsInstance(m, lesana.Entry) def test_entry_from_eid(self): self.collection = lesana.Collection('tests/data/simple') entry = self.collection.entry_from_eid( '11189ee47ddf4796b718a483b379f976' ) self.assertEqual(entry.eid, '11189ee47ddf4796b718a483b379f976') self.collection.safe = True entry = self.collection.entry_from_eid( '11189ee47ddf4796b718a483b379f976' ) self.assertEqual(entry.eid, '11189ee47ddf4796b718a483b379f976') def test_entry_from_short_eid(self): self.collection = lesana.Collection('tests/data/simple') entries = self.collection.entries_from_short_eid( '11189ee4' ) self.assertEqual(len(entries), 1) self.assertEqual(entries[0].eid, '11189ee47ddf4796b718a483b379f976') entries = self.collection.entries_from_short_eid( '11189ee47ddf4796b718a483b379f976' ) self.assertEqual(len(entries), 1) self.assertEqual(entries[0].eid, '11189ee47ddf4796b718a483b379f976') entries = self.collection.entries_from_short_eid( '12345678' ) self.assertEqual(len(entries), 0) def test_index_missing_file(self): self.collection = lesana.Collection('tests/data/simple') with self.assertLogs(level=logging.WARNING) as cm: self.collection.update_cache(['non_existing_file']) self.assertEqual(len(cm.output), 1) self.assertIn("non_existing_file", cm.output[0]) def test_get_entry_missing_eid(self): self.collection = lesana.Collection('tests/data/simple') entry = self.collection.entry_from_eid('this is not an eid') self.assertIsNone(entry) def test_render_collection(self): self.collection = lesana.Collection('tests/data/simple') template = self.collection.get_template( 'tests/data/simple/templates/collection_template.txt' ) res = template.render(entries=self.collection.get_all_documents()) self.assertIn('11189ee4: Another item', res) class testSimpleCollection(unittest.TestCase): def setUp(self): self.tmpdir = tempfile.mkdtemp() shutil.copytree('tests/data/simple', self.tmpdir, dirs_exist_ok=True) self.collection = lesana.Collection(self.tmpdir) def tearDown(self): shutil.rmtree(self.tmpdir) def test_update(self): self.collection.update_field('Item', field="position", value="new_pos") with open(os.path.join( self.collection.basedir, 'items', '11189ee47ddf4796b718a483b379f976.yaml' )) as fp: self.assertIn("new_pos", fp.read()) pass self.assertEqual( self.collection.entry_from_eid( "11189ee47ddf4796b718a483b379f976" ).data['position'], "new_pos" ) self.assertIsNone( self.collection.entry_from_eid( "8b69b063b2a64db7b5714294a69255c7" ).data['position'] ) class testEntries(unittest.TestCase): def setUp(self): self.collection = lesana.Collection('tests/data/simple') self.basepath = 'tests/data/simple/items' self.filenames = [] def tearDown(self): for fname in self.filenames: os.remove(fname) shutil.rmtree(os.path.join(self.collection.basedir, '.lesana')) def test_simple(self): fname = '085682ed-6792-499d-a3ab-9aebd683c011.yaml' with open(os.path.join(self.basepath, fname)) as fp: data = ruamel.yaml.safe_load(fp) entry = lesana.Entry(self.collection, data=data, fname=fname) self.assertEqual(entry.idterm, 'Q'+data['eid']) fname = '11189ee47ddf4796b718a483b379f976.yaml' eid = '11189ee47ddf4796b718a483b379f976' with open(os.path.join(self.basepath, fname)) as fp: data = ruamel.yaml.safe_load(fp) entry = lesana.Entry(self.collection, data=data, fname=fname) self.assertEqual(entry.idterm, 'Q'+eid) self.assertEqual(entry.short_id, eid[:8]) def test_write_new(self): new_entry = lesana.Entry(self.collection) self.collection.save_entries(entries=[new_entry]) entry_fname = 'tests/data/simple/items/' + new_entry.fname self.filenames.append(entry_fname) with open(entry_fname) as fp: text = fp.read() self.assertIn('quantity (integer): how many items are there', text) self.assertIn('other (yaml):', text) self.assertNotIn('position (string)', text) written = ruamel.yaml.safe_load(text) self.assertIsInstance(written['quantity'], int) self.assertIsInstance(written['name'], str) def test_entry_representation(self): eid = '11189ee47ddf4796b718a483b379f976' entry = self.collection.entry_from_eid(eid) self.assertEqual( str(entry), eid ) label = '{{ eid }}: {{ name }}' self.collection.settings['entry_label'] = label self.assertEqual( str(entry), '{eid}: {name}'.format(eid=eid, name='Another item') ) def test_entry_creation_eid_but_no_filename(self): fname = '11189ee47ddf4796b718a483b379f976.yaml' with open(os.path.join(self.basepath, fname)) as fp: data = ruamel.yaml.safe_load(fp) data['eid'] = '11189ee47ddf4796b718a483b379f976' entry = lesana.Entry(self.collection, data=data) self.assertEqual(entry.fname, fname) def test_entry_creation_no_eid_no_filename(self): fname = '11189ee47ddf4796b718a483b379f976.yaml' with open(os.path.join(self.basepath, fname)) as fp: data = ruamel.yaml.safe_load(fp) entry = lesana.Entry(self.collection, data=data) self.assertIsNotNone(entry.eid) self.assertIsNotNone(entry.fname) def test_entry_creation_filename_but_no_eid(self): fname = '11189ee47ddf4796b718a483b379f976.yaml' eid = '11189ee47ddf4796b718a483b379f976' with open(os.path.join(self.basepath, fname)) as fp: data = ruamel.yaml.safe_load(fp) entry = lesana.Entry(self.collection, data=data, fname=fname) self.assertEqual(entry.eid, eid) def test_entry_str_filename_and_eid(self): fname = '11189ee47ddf4796b718a483b379f976.yaml' with open(os.path.join(self.basepath, fname)) as fp: data = ruamel.yaml.safe_load(fp) data['eid'] = '11189ee47ddf4796b718a483b379f976' entry = lesana.Entry(self.collection, data=data) self.assertEqual(str(entry), data['eid']) self.collection.settings['entry_label'] = '{{ eid }}: {{ name }}' self.assertEqual(str(entry), data['eid'] + ': Another item') def test_entry_str_filename_no_eid(self): fname = '11189ee47ddf4796b718a483b379f976.yaml' with open(os.path.join(self.basepath, fname)) as fp: data = ruamel.yaml.safe_load(fp) entry = lesana.Entry(self.collection, data=data) eid = entry.eid self.assertEqual(str(entry), eid) self.collection.settings['entry_label'] = '{{ eid }}: {{ name }}' self.assertEqual(str(entry), eid + ': Another item') def test_render_entry(self): fname = '11189ee47ddf4796b718a483b379f976.yaml' with open(os.path.join(self.basepath, fname)) as fp: data = ruamel.yaml.safe_load(fp) entry = lesana.Entry(self.collection, data=data) eid = entry.eid res = entry.render('tests/data/simple/templates/trivial_template.txt') self.assertIn(eid, res) def test_empty_data(self): entry = lesana.Entry(self.collection) self.assertIn("name: ''", entry.yaml_data) self.assertIn('quantity: 0', entry.yaml_data) class testComplexCollection(unittest.TestCase): @classmethod def setUpClass(self): self.collection = lesana.Collection('tests/data/complex') @classmethod def tearDownClass(self): shutil.rmtree(os.path.join(self.collection.basedir, '.lesana')) def test_init(self): self.assertIsNotNone(self.collection.settings) self.assertEqual( self.collection.settings['name'], "Fully featured lesana collection" ) self.assertEqual(len(self.collection.settings['fields']), 9) self.assertIsNotNone(self.collection.stemmer) self.assertEqual(len(self.collection.indexed_fields), 6) def test_index(self): self.collection.update_cache() def test_indexing_list(self): self.collection.update_cache(['73097121f1874a6ea2f927db7dc4f11e.yaml']) self.collection.start_search('tags:this') res = self.collection.get_search_results() matches = list(res) self.assertEqual(len(matches), 1) for m in matches: self.assertIsInstance(m, lesana.Entry) def test_boolean_field(self): entry = self.collection.entry_from_eid( '73097121f1874a6ea2f927db7dc4f11e' ) self.assertIsInstance(entry.data['exists'], bool) def test_empty_data(self): entry = lesana.Entry(self.collection) print(entry.yaml_data) self.assertIn("name: ''", entry.yaml_data) self.assertIn('with_default', entry.yaml_data) self.assertIn('amount: 0', entry.yaml_data) class testCollectionWithErrors(unittest.TestCase): @classmethod def setUpClass(self): self.collection = lesana.Collection('tests/data/wrong') @classmethod def tearDownClass(self): shutil.rmtree(os.path.join(self.collection.basedir, '.lesana')) def test_init(self): self.assertIsNotNone(self.collection.settings) self.assertEqual( self.collection.settings['name'], "Lesana collection with certain errors" ) self.assertEqual(len(self.collection.settings['fields']), 7) self.assertIsNotNone(self.collection.stemmer) self.assertEqual(len(self.collection.indexed_fields), 3) def test_index(self): loaded = self.collection.update_cache() self.assertEqual(loaded, 0) class testCollectionCreation(unittest.TestCase): def test_init(self): tmpdir = tempfile.mkdtemp() collection = lesana.Collection.init(tmpdir) self.assertIsInstance(collection, lesana.Collection) self.assertTrue(os.path.isdir(os.path.join(tmpdir, '.git'))) self.assertTrue(os.path.isdir(os.path.join(tmpdir, '.lesana'))) self.assertTrue(os.path.isfile(os.path.join(tmpdir, 'settings.yaml'))) self.assertTrue(os.path.isfile(os.path.join(tmpdir, '.gitignore'))) # and then run it twice on the same directory, nothing should break collection = lesana.Collection.init(tmpdir) self.assertIsInstance(collection, lesana.Collection) self.assertTrue(os.path.isdir(os.path.join(tmpdir, '.git'))) self.assertTrue(os.path.isdir(os.path.join(tmpdir, '.lesana'))) self.assertTrue(os.path.isfile(os.path.join(tmpdir, 'settings.yaml'))) self.assertTrue(os.path.isfile(os.path.join(tmpdir, '.gitignore'))) created = lesana.Collection(tmpdir) self.assertTrue(created.settings['git']) shutil.rmtree(tmpdir) def _do_nothing(*args, **kwargs): # A function that does nothing instead of editing a file pass def test_init_edit_file(self): tmpdir = tempfile.mkdtemp() collection = lesana.Collection.init(tmpdir, edit_file=self._do_nothing) self.assertIsInstance(collection, lesana.Collection) self.assertTrue(os.path.isdir(os.path.join(tmpdir, '.git'))) self.assertTrue(os.path.isdir(os.path.join(tmpdir, '.lesana'))) self.assertTrue(os.path.isfile(os.path.join(tmpdir, 'settings.yaml'))) self.assertTrue(os.path.isfile(os.path.join(tmpdir, '.gitignore'))) shutil.rmtree(tmpdir) def test_init_no_git(self): tmpdir = tempfile.mkdtemp() collection = lesana.Collection.init(tmpdir, git_enabled=False) self.assertIsInstance(collection, lesana.Collection) self.assertFalse(os.path.isdir(os.path.join(tmpdir, '.git'))) self.assertTrue(os.path.isdir(os.path.join(tmpdir, '.lesana'))) self.assertTrue(os.path.isfile(os.path.join(tmpdir, 'settings.yaml'))) self.assertFalse(os.path.isfile(os.path.join(tmpdir, '.gitignore'))) # and then run it twice on the same directory, nothing should break collection = lesana.Collection.init(tmpdir, git_enabled=False) self.assertIsInstance(collection, lesana.Collection) self.assertFalse(os.path.isdir(os.path.join(tmpdir, '.git'))) self.assertTrue(os.path.isdir(os.path.join(tmpdir, '.lesana'))) self.assertTrue(os.path.isfile(os.path.join(tmpdir, 'settings.yaml'))) self.assertFalse(os.path.isfile(os.path.join(tmpdir, '.gitignore'))) created = lesana.Collection(tmpdir) self.assertFalse(created.settings['git']) shutil.rmtree(tmpdir) def test_deletion(self): tmpdir = tempfile.mkdtemp() shutil.copy('tests/data/simple/settings.yaml', tmpdir) shutil.copytree( 'tests/data/simple/items', os.path.join(tmpdir, 'items'), ) collection = lesana.Collection.init(tmpdir) # We start with one item indexed with the term "another" collection.start_search('another') mset = collection._enquire.get_mset(0, 10) self.assertEqual(mset.get_matches_estimated(), 1) # Then delete it collection.remove_entries(['11189ee47ddf4796b718a483b379f976']) # An now we should have none self.assertFalse(os.path.exists(os.path.join( tmpdir, 'items', '11189ee47ddf4796b718a483b379f976.yaml' ))) collection.start_search('another') mset = collection._enquire.get_mset(0, 10) self.assertEqual(mset.get_matches_estimated(), 0) def test_partial_eid_deletion(self): tmpdir = tempfile.mkdtemp() shutil.copy('tests/data/simple/settings.yaml', tmpdir) shutil.copytree( 'tests/data/simple/items', os.path.join(tmpdir, 'items'), ) collection = lesana.Collection.init(tmpdir) # We start with one item indexed with the term "another" collection.start_search('another') mset = collection._enquire.get_mset(0, 10) self.assertEqual(mset.get_matches_estimated(), 1) # Then delete it, using the short id collection.remove_entries(['11189ee4']) # An now we should have none self.assertFalse(os.path.exists(os.path.join( tmpdir, 'items', '11189ee47ddf4796b718a483b379f976.yaml' ))) collection.start_search('another') mset = collection._enquire.get_mset(0, 10) self.assertEqual(mset.get_matches_estimated(), 0) def _find_file_in_git_index(self, fname, index): found = False for (path, stage) in index.entries: if fname in path: found = True break return found def test_git_adding(self): tmpdir = tempfile.mkdtemp() shutil.copy('tests/data/simple/settings.yaml', tmpdir) shutil.copytree( 'tests/data/simple/items', os.path.join(tmpdir, 'items'), ) collection = lesana.Collection.init(tmpdir) fname = '11189ee47ddf4796b718a483b379f976.yaml' repo = git.Repo(tmpdir) # By default, this collection doesn't have any git entry in the # settings (but there is a repo) collection.git_add_files([os.path.join(collection.itemdir, fname)]) self.assertFalse(self._find_file_in_git_index(fname, repo.index)) # Then we set it to false collection.settings['git'] = False collection.git_add_files([os.path.join(collection.itemdir, fname)]) self.assertFalse(self._find_file_in_git_index(fname, repo.index)) # And only when it's set to true we should find the file in the # staging area collection.settings['git'] = True collection.git_add_files([os.path.join(collection.itemdir, fname)]) self.assertTrue(self._find_file_in_git_index(fname, repo.index)) shutil.rmtree(tmpdir) def test_init_custom_settings(self): tmpdir = tempfile.mkdtemp() collection = lesana.Collection.init( tmpdir, edit_file=self._do_nothing, settings={ 'name': 'A different name', 'fields': [ {'name': 'title', 'type': 'string'}, {'name': 'author', 'type': 'string'}, ], }, ) self.assertIsInstance(collection, lesana.Collection) self.assertTrue(os.path.isfile(os.path.join(tmpdir, 'settings.yaml'))) self.assertEqual(collection.settings['name'], 'A different name') self.assertEqual(len(collection.settings['fields']), 2) shutil.rmtree(tmpdir) if __name__ == '__main__': unittest.main()