diff --git a/openlp/plugins/bibles/lib/bibleimport.py b/openlp/plugins/bibles/lib/bibleimport.py index eaef01aed..53f3a55e3 100644 --- a/openlp/plugins/bibles/lib/bibleimport.py +++ b/openlp/plugins/bibles/lib/bibleimport.py @@ -23,23 +23,21 @@ from lxml import etree, objectify from zipfile import is_zipfile -from openlp.core.common import OpenLPMixin, languages, translate +from openlp.core.common import OpenLPMixin, Registry, RegistryProperties, languages, translate from openlp.core.lib import ValidationError from openlp.core.lib.ui import critical_error_message_box -from openlp.plugins.bibles.lib.db import BibleDB, BiblesResourcesDB +from openlp.plugins.bibles.lib.db import AlternativeBookNamesDB, BibleDB, BiblesResourcesDB -class BibleImport(OpenLPMixin, BibleDB): +class BibleImport(OpenLPMixin, RegistryProperties, BibleDB): """ Helper class to import bibles from a third party source into OpenLP """ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.filename = kwargs['filename'] if 'filename' in kwargs else None - - def set_current_chapter(self, book_name, chapter_name): - self.wizard.increment_progress_bar(translate('BiblesPlugin.OsisImport', 'Importing {book} {chapter}...') - .format(book=book_name, chapter=chapter_name)) + self.wizard = None + Registry().register_function('openlp_stop_wizard', self.stop_import) @staticmethod def is_compressed(file): @@ -56,6 +54,45 @@ class BibleImport(OpenLPMixin, BibleDB): return True return False + def get_book_ref_id_by_name(self, book, maxbooks, language_id=None): + self.log_debug('BibleDB.get_book_ref_id_by_name:("{book}", "{lang}")'.format(book=book, lang=language_id)) + book_id = None + if BiblesResourcesDB.get_book(book, True): + book_temp = BiblesResourcesDB.get_book(book, True) + book_id = book_temp['id'] + elif BiblesResourcesDB.get_alternative_book_name(book): + book_id = BiblesResourcesDB.get_alternative_book_name(book) + elif AlternativeBookNamesDB.get_book_reference_id(book): + book_id = AlternativeBookNamesDB.get_book_reference_id(book) + else: + from openlp.plugins.bibles.forms import BookNameForm + book_name = BookNameForm(self.wizard) + if book_name.exec(book, self.get_books(), maxbooks): + book_id = book_name.book_id + if book_id: + AlternativeBookNamesDB.create_alternative_book_name( + book, book_id, language_id) + return book_id + + def get_language(self, bible_name=None): + """ + If no language is given it calls a dialog window where the user could select the bible language. + Return the language id of a bible. + + :param bible_name: The language the bible is. + """ + self.log_debug('BibleImpoer.get_language()') + from openlp.plugins.bibles.forms import LanguageForm + language_id = None + language_form = LanguageForm(self.wizard) + if language_form.exec(bible_name): + combo_box = language_form.language_combo_box + language_id = combo_box.itemData(combo_box.currentIndex()) + if not language_id: + return None + self.save_meta('language_id', language_id) + return language_id + def get_language_id(self, file_language=None, bible_name=None): """ Get the language_id for the language of the bible. Fallback to user input if we cannot do this pragmatically. @@ -138,6 +175,28 @@ class BibleImport(OpenLPMixin, BibleDB): .format(file_name=e.filename, error=e.strerror)) return None + def register(self, wizard): + """ + This method basically just initialises the database. It is called from the Bible Manager when a Bible is + imported. Descendant classes may want to override this method to supply their own custom + initialisation as well. + + :param wizard: The actual Qt wizard form. + """ + self.wizard = wizard + return self.name + + def set_current_chapter(self, book_name, chapter_name): + self.wizard.increment_progress_bar(translate('BiblesPlugin.OsisImport', 'Importing {book} {chapter}...') + .format(book=book_name, chapter=chapter_name)) + + def stop_import(self): + """ + Stops the import of the Bible. + """ + self.log_debug('Stopping import') + self.stop_import_flag = True + def validate_xml_file(self, filename, tag): """ Validate the supplied file diff --git a/openlp/plugins/bibles/lib/db.py b/openlp/plugins/bibles/lib/db.py index e5142ae98..e7d29d016 100644 --- a/openlp/plugins/bibles/lib/db.py +++ b/openlp/plugins/bibles/lib/db.py @@ -33,7 +33,7 @@ from sqlalchemy.exc import OperationalError from sqlalchemy.orm import class_mapper, mapper, relation from sqlalchemy.orm.exc import UnmappedClassError -from openlp.core.common import Registry, RegistryProperties, AppLocation, translate, clean_filename +from openlp.core.common import AppLocation, translate, clean_filename from openlp.core.lib.db import BaseModel, init_db, Manager from openlp.core.lib.ui import critical_error_message_box from openlp.plugins.bibles.lib import upgrade @@ -106,7 +106,7 @@ def init_schema(url): return session -class BibleDB(Manager, RegistryProperties): +class BibleDB(Manager): """ This class represents a database-bound Bible. It is used as a base class for all the custom importers, so that the can implement their own import methods, but benefit from the database methods in here via inheritance, @@ -153,15 +153,6 @@ class BibleDB(Manager, RegistryProperties): self.get_name() if 'path' in kwargs: self.path = kwargs['path'] - self.wizard = None - Registry().register_function('openlp_stop_wizard', self.stop_import) - - def stop_import(self): - """ - Stops the import of the Bible. - """ - log.debug('Stopping import') - self.stop_import_flag = True def get_name(self): """ @@ -171,17 +162,6 @@ class BibleDB(Manager, RegistryProperties): self.name = version_name.value if version_name else None return self.name - def register(self, wizard): - """ - This method basically just initialises the database. It is called from the Bible Manager when a Bible is - imported. Descendant classes may want to override this method to supply their own custom - initialisation as well. - - :param wizard: The actual Qt wizard form. - """ - self.wizard = wizard - return self.name - def create_book(self, name, bk_ref_id, testament=1): """ Add a book to the database. @@ -306,26 +286,6 @@ class BibleDB(Manager, RegistryProperties): log.debug('BibleDB.get_book_by_book_ref_id("{ref}")'.format(ref=ref_id)) return self.get_object_filtered(Book, Book.book_reference_id.like(ref_id)) - def get_book_ref_id_by_name(self, book, maxbooks, language_id=None): - log.debug('BibleDB.get_book_ref_id_by_name:("{book}", "{lang}")'.format(book=book, lang=language_id)) - book_id = None - if BiblesResourcesDB.get_book(book, True): - book_temp = BiblesResourcesDB.get_book(book, True) - book_id = book_temp['id'] - elif BiblesResourcesDB.get_alternative_book_name(book): - book_id = BiblesResourcesDB.get_alternative_book_name(book) - elif AlternativeBookNamesDB.get_book_reference_id(book): - book_id = AlternativeBookNamesDB.get_book_reference_id(book) - else: - from openlp.plugins.bibles.forms import BookNameForm - book_name = BookNameForm(self.wizard) - if book_name.exec(book, self.get_books(), maxbooks): - book_id = book_name.book_id - if book_id: - AlternativeBookNamesDB.create_alternative_book_name( - book, book_id, language_id) - return book_id - def get_book_ref_id_by_localised_name(self, book, language_selection): """ Return the id of a named book. @@ -462,25 +422,6 @@ class BibleDB(Manager, RegistryProperties): return 0 return count - def get_language(self, bible_name=None): - """ - If no language is given it calls a dialog window where the user could select the bible language. - Return the language id of a bible. - - :param bible_name: The language the bible is. - """ - log.debug('BibleDB.get_language()') - from openlp.plugins.bibles.forms import LanguageForm - language_id = None - language_form = LanguageForm(self.wizard) - if language_form.exec(bible_name): - combo_box = language_form.language_combo_box - language_id = combo_box.itemData(combo_box.currentIndex()) - if not language_id: - return None - self.save_meta('language_id', language_id) - return language_id - def dump_bible(self): """ Utility debugging method to dump the contents of a bible. diff --git a/tests/functional/openlp_plugins/bibles/test_bibleimport.py b/tests/functional/openlp_plugins/bibles/test_bibleimport.py index 50baa655b..30ab45352 100644 --- a/tests/functional/openlp_plugins/bibles/test_bibleimport.py +++ b/tests/functional/openlp_plugins/bibles/test_bibleimport.py @@ -62,6 +62,9 @@ class TestBibleImport(TestCase): side_effect=lambda module, string_to_translate, *args: string_to_translate) self.addCleanup(self.translate_patcher.stop) self.mocked_translate = self.translate_patcher.start() + self.registry_patcher = patch('openlp.plugins.bibles.lib.bibleimport.Registry') + self.addCleanup(self.registry_patcher.stop) + self.registry_patcher.start() def init_kwargs_none_test(self): """ @@ -88,6 +91,54 @@ class TestBibleImport(TestCase): self.assertEqual(instance.filename, 'bible.xml') self.assertIsInstance(instance, BibleDB) + def get_language_canceled_test(self): + """ + Test the BibleImport.get_language method when the user rejects the dialog box + """ + # GIVEN: A mocked LanguageForm with an exec method which returns QtDialog.Rejected and an instance of BibleDB + with patch.object(BibleDB, '_setup'), patch('openlp.plugins.bibles.forms.LanguageForm') as mocked_language_form: + + # The integer value of QtDialog.Rejected is 0. Using the enumeration causes a seg fault for some reason + mocked_language_form_instance = MagicMock(**{'exec.return_value': 0}) + mocked_language_form.return_value = mocked_language_form_instance + instance = BibleImport(MagicMock()) + mocked_wizard = MagicMock() + instance.wizard = mocked_wizard + + # WHEN: Calling get_language() + result = instance.get_language() + + # THEN: get_language() should return False + mocked_language_form.assert_called_once_with(mocked_wizard) + mocked_language_form_instance.exec.assert_called_once_with(None) + self.assertFalse(result, 'get_language() should return False if the user rejects the dialog box') + + def get_language_accepted_test(self): + """ + Test the BibleImport.get_language method when the user accepts the dialog box + """ + # GIVEN: A mocked LanguageForm with an exec method which returns QtDialog.Accepted an instance of BibleDB and + # a combobox with the selected item data as 10 + with patch.object(BibleDB, 'save_meta'), patch.object(BibleDB, '_setup'), \ + patch('openlp.plugins.bibles.forms.LanguageForm') as mocked_language_form: + + # The integer value of QtDialog.Accepted is 1. Using the enumeration causes a seg fault for some reason + mocked_language_form_instance = MagicMock(**{'exec.return_value': 1, + 'language_combo_box.itemData.return_value': 10}) + mocked_language_form.return_value = mocked_language_form_instance + instance = BibleImport(MagicMock()) + mocked_wizard = MagicMock() + instance.wizard = mocked_wizard + + # WHEN: Calling get_language() + result = instance.get_language('Bible Name') + + # THEN: get_language() should return the id of the selected language in the combo box + mocked_language_form.assert_called_once_with(mocked_wizard) + mocked_language_form_instance.exec.assert_called_once_with('Bible Name') + self.assertEqual(result, 10, 'get_language() should return the id of the language the user has chosen when ' + 'they accept the dialog box') + def get_language_id_language_found_test(self): """ Test get_language_id() when called with a name found in the languages list @@ -172,6 +223,38 @@ class TestBibleImport(TestCase): self.assertFalse(instance.save_meta.called) self.assertIsNone(result) + def is_compressed_compressed_test(self): + """ + Test is_compressed when the 'file' being tested is compressed + """ + # GIVEN: An instance of BibleImport and a mocked is_zipfile which returns True + with patch('openlp.plugins.bibles.lib.bibleimport.is_zipfile', return_value=True): + instance = BibleImport(MagicMock()) + + # WHEN: Calling is_compressed + result = instance.is_compressed('file.ext') + + # THEN: Then critical_error_message_box should be called informing the user that the file is compressed and + # True should be returned + self.mocked_critical_error_message_box.assert_called_once_with( + message='The file "file.ext" you supplied is compressed. You must decompress it before import.') + self.assertTrue(result) + + def is_compressed_not_compressed_test(self): + """ + Test is_compressed when the 'file' being tested is compressed + """ + # GIVEN: An instance of BibleImport and a mocked is_zipfile which returns True + with patch('openlp.plugins.bibles.lib.bibleimport.is_zipfile', return_value=False): + instance = BibleImport(MagicMock()) + + # WHEN: Calling is_compressed + result = instance.is_compressed('file.ext') + + # THEN: False should be returned and critical_error_message_box should not have been called + self.assertFalse(result) + self.assertFalse(self.mocked_critical_error_message_box.called) + def parse_xml_etree_test(self): """ Test BibleImport.parse_xml() when called with the use_objectify default value @@ -259,27 +342,6 @@ class TestBibleImport(TestCase): # THEN: The result returned should contain the correct data self.assertEqual(etree.tostring(result), b'\n Testdatatokeep\n \n') - def parse_xml_file_file_not_found_exception_test(self): - """ - Test that validate_xml_file raises a ValidationError with an OpenSong root tag - """ - # GIVEN: A mocked open which raises a FileNotFoundError and an instance of BibleImporter - exception = FileNotFoundError() - exception.filename = 'file.tst' - exception.strerror = 'No such file or directory' - self.mocked_open.side_effect = exception - importer = BibleImport(MagicMock(), path='.', name='.', filename='') - - # WHEN: Calling parse_xml - result = importer.parse_xml('file.tst') - - # THEN: parse_xml should have caught the error, informed the user and returned None - self.mocked_log.exception.assert_called_once_with('Opening file.tst failed.') - self.mocked_critical_error_message_box.assert_called_once_with( - title='An Error Occured When Opening A File', - message='The following error occurred when trying to open\nfile.tst:\n\nNo such file or directory') - self.assertIsNone(result) - def parse_xml_file_file_not_found_exception_test(self): """ Test that parse_xml handles a FileNotFoundError exception correctly @@ -324,6 +386,20 @@ class TestBibleImport(TestCase): message='The following error occurred when trying to open\nfile.tst:\n\nPermission denied') self.assertIsNone(result) + def set_current_chapter_test(self): + """ + Test set_current_chapter + """ + # GIVEN: An instance of BibleImport and a mocked wizard + importer = BibleImport(MagicMock(), path='.', name='.', filename='') + importer.wizard = MagicMock() + + # WHEN: Calling set_current_chapter + importer.set_current_chapter('Book_Name', 'Chapter') + + # THEN: Increment_progress_bar should have been called with a text string + importer.wizard.increment_progress_bar.assert_called_once_with('Importing Book_Name Chapter...') + def validate_xml_file_compressed_file_test(self): """ Test that validate_xml_file raises a ValidationError when is_compressed returns True diff --git a/tests/functional/openlp_plugins/bibles/test_csvimport.py b/tests/functional/openlp_plugins/bibles/test_csvimport.py index a4a19279e..8eff7274e 100644 --- a/tests/functional/openlp_plugins/bibles/test_csvimport.py +++ b/tests/functional/openlp_plugins/bibles/test_csvimport.py @@ -48,7 +48,7 @@ class TestCSVImport(TestCase): self.manager_patcher = patch('openlp.plugins.bibles.lib.db.Manager') self.addCleanup(self.manager_patcher.stop) self.manager_patcher.start() - self.registry_patcher = patch('openlp.plugins.bibles.lib.db.Registry') + self.registry_patcher = patch('openlp.plugins.bibles.lib.bibleimport.Registry') self.addCleanup(self.registry_patcher.stop) self.registry_patcher.start() diff --git a/tests/functional/openlp_plugins/bibles/test_db.py b/tests/functional/openlp_plugins/bibles/test_db.py index 2807a8a3e..75e008953 100644 --- a/tests/functional/openlp_plugins/bibles/test_db.py +++ b/tests/functional/openlp_plugins/bibles/test_db.py @@ -25,63 +25,9 @@ This module contains tests for the db submodule of the Bibles plugin. from unittest import TestCase -from openlp.plugins.bibles.lib.db import BibleDB -from tests.functional import MagicMock, patch - class TestBibleDB(TestCase): """ Test the functions in the BibleDB class. """ - - def test_get_language_canceled(self): - """ - Test the BibleDB.get_language method when the user rejects the dialog box - """ - # GIVEN: A mocked LanguageForm with an exec method which returns QtDialog.Rejected and an instance of BibleDB - with patch('openlp.plugins.bibles.lib.db.BibleDB._setup'),\ - patch('openlp.plugins.bibles.forms.LanguageForm') as mocked_language_form: - - # The integer value of QtDialog.Rejected is 0. Using the enumeration causes a seg fault for some reason - mocked_language_form_instance = MagicMock(**{'exec.return_value': 0}) - mocked_language_form.return_value = mocked_language_form_instance - mocked_parent = MagicMock() - instance = BibleDB(mocked_parent) - mocked_wizard = MagicMock() - instance.wizard = mocked_wizard - - # WHEN: Calling get_language() - result = instance.get_language() - - # THEN: get_language() should return False - mocked_language_form.assert_called_once_with(mocked_wizard) - mocked_language_form_instance.exec.assert_called_once_with(None) - self.assertFalse(result, 'get_language() should return False if the user rejects the dialog box') - - def test_get_language_accepted(self): - """ - Test the BibleDB.get_language method when the user accepts the dialog box - """ - # GIVEN: A mocked LanguageForm with an exec method which returns QtDialog.Accepted an instance of BibleDB and - # a combobox with the selected item data as 10 - with patch('openlp.plugins.bibles.lib.db.BibleDB._setup'), \ - patch('openlp.plugins.bibles.lib.db.BibleDB.save_meta'), \ - patch('openlp.plugins.bibles.forms.LanguageForm') as mocked_language_form: - - # The integer value of QtDialog.Accepted is 1. Using the enumeration causes a seg fault for some reason - mocked_language_form_instance = MagicMock(**{'exec.return_value': 1, - 'language_combo_box.itemData.return_value': 10}) - mocked_language_form.return_value = mocked_language_form_instance - mocked_parent = MagicMock() - instance = BibleDB(mocked_parent) - mocked_wizard = MagicMock() - instance.wizard = mocked_wizard - - # WHEN: Calling get_language() - result = instance.get_language('Bible Name') - - # THEN: get_language() should return the id of the selected language in the combo box - mocked_language_form.assert_called_once_with(mocked_wizard) - mocked_language_form_instance.exec.assert_called_once_with('Bible Name') - self.assertEqual(result, 10, 'get_language() should return the id of the language the user has chosen when ' - 'they accept the dialog box') + pass diff --git a/tests/functional/openlp_plugins/bibles/test_osisimport.py b/tests/functional/openlp_plugins/bibles/test_osisimport.py index dd0f661a0..eaaea7206 100644 --- a/tests/functional/openlp_plugins/bibles/test_osisimport.py +++ b/tests/functional/openlp_plugins/bibles/test_osisimport.py @@ -49,7 +49,7 @@ class TestOsisImport(TestCase): self.find_and_create_book_patch = patch.object(BibleImport, 'find_and_create_book') self.addCleanup(self.find_and_create_book_patch.stop) self.mocked_find_and_create_book = self.find_and_create_book_patch.start() - self.registry_patcher = patch('openlp.plugins.bibles.lib.db.Registry') + self.registry_patcher = patch('openlp.plugins.bibles.lib.bibleimport.Registry') self.addCleanup(self.registry_patcher.stop) self.registry_patcher.start() self.manager_patcher = patch('openlp.plugins.bibles.lib.db.Manager') @@ -409,7 +409,7 @@ class TestOsisImportFileImports(TestCase): Test the functions in the :mod:`osisimport` module. """ def setUp(self): - self.registry_patcher = patch('openlp.plugins.bibles.lib.db.Registry') + self.registry_patcher = patch('openlp.plugins.bibles.lib.bibleimport.Registry') self.addCleanup(self.registry_patcher.stop) self.registry_patcher.start() self.manager_patcher = patch('openlp.plugins.bibles.lib.db.Manager') diff --git a/tests/functional/openlp_plugins/bibles/test_swordimport.py b/tests/functional/openlp_plugins/bibles/test_swordimport.py index 51e629f53..261df1c0e 100644 --- a/tests/functional/openlp_plugins/bibles/test_swordimport.py +++ b/tests/functional/openlp_plugins/bibles/test_swordimport.py @@ -46,7 +46,7 @@ class TestSwordImport(TestCase): """ def setUp(self): - self.registry_patcher = patch('openlp.plugins.bibles.lib.db.Registry') + self.registry_patcher = patch('openlp.plugins.bibles.lib.bibleimport.Registry') self.registry_patcher.start() self.manager_patcher = patch('openlp.plugins.bibles.lib.db.Manager') self.manager_patcher.start() diff --git a/tests/functional/openlp_plugins/bibles/test_zefaniaimport.py b/tests/functional/openlp_plugins/bibles/test_zefaniaimport.py index 11fcfb7e3..510961a65 100644 --- a/tests/functional/openlp_plugins/bibles/test_zefaniaimport.py +++ b/tests/functional/openlp_plugins/bibles/test_zefaniaimport.py @@ -41,7 +41,7 @@ class TestZefaniaImport(TestCase): """ def setUp(self): - self.registry_patcher = patch('openlp.plugins.bibles.lib.db.Registry') + self.registry_patcher = patch('openlp.plugins.bibles.lib.bibleimport.Registry') self.addCleanup(self.registry_patcher.stop) self.registry_patcher.start() self.manager_patcher = patch('openlp.plugins.bibles.lib.db.Manager')