Merge lp:~phill-ridout/openlp/even-more-refactors into lp:openlp
- even-more-refactors
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Tim Bentley |
Approved revision: | 2707 |
Merged at revision: | 2696 |
Proposed branch: | lp:~phill-ridout/openlp/even-more-refactors |
Merge into: | lp:openlp |
Diff against target: |
3154 lines (+1623/-771) 24 files modified
openlp/core/common/openlpmixin.py (+6/-0) openlp/plugins/bibles/bibleplugin.py (+4/-4) openlp/plugins/bibles/forms/bibleimportform.py (+24/-16) openlp/plugins/bibles/lib/__init__.py (+2/-2) openlp/plugins/bibles/lib/bibleimport.py (+150/-29) openlp/plugins/bibles/lib/db.py (+2/-62) openlp/plugins/bibles/lib/importers/csvbible.py (+15/-31) openlp/plugins/bibles/lib/importers/opensong.py (+112/-95) openlp/plugins/bibles/lib/importers/osis.py (+93/-97) openlp/plugins/bibles/lib/importers/zefania.py (+4/-3) openlp/plugins/bibles/lib/manager.py (+3/-3) openlp/plugins/bibles/lib/upgrade.py (+2/-164) tests/functional/openlp_core_ui/test_exceptionform.py (+1/-6) tests/functional/openlp_plugins/bibles/test_bibleimport.py (+437/-34) tests/functional/openlp_plugins/bibles/test_csvimport.py (+11/-77) tests/functional/openlp_plugins/bibles/test_db.py (+1/-55) tests/functional/openlp_plugins/bibles/test_opensongimport.py (+343/-31) tests/functional/openlp_plugins/bibles/test_osisimport.py (+367/-14) tests/functional/openlp_plugins/bibles/test_swordimport.py (+1/-1) tests/functional/openlp_plugins/bibles/test_zefaniaimport.py (+5/-7) tests/resources/bibles/dk1933.json (+10/-10) tests/resources/bibles/kjv.json (+10/-10) tests/resources/bibles/rst.json (+10/-10) tests/resources/bibles/web.json (+10/-10) |
To merge this branch: | bzr merge lp:~phill-ridout/openlp/even-more-refactors |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Tim Bentley | Approve | ||
Tomas Groth | Approve | ||
Review via email: mp+305388@code.launchpad.net |
Commit message
Description of the change
Some more bible refactors
lp:~phill-ridout/openlp/even-more-refactors (revision 2707)
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
[SUCCESS] https:/
Process finished with exit code 0
Phill (phill-ridout) wrote : | # |
> Sorry one small change needed.
Any chance you can let this one slide? I'm not going to be in a position to correct this for a week. I'll sort it in my next round of Bible refractors if that's ok with you? Unless tgc or superfly pick up on something else!
Tim Bentley (trb143) wrote : | # |
Ok it was a real nit pick!
Tomas Groth (tomasgroth) : | # |
Preview Diff
1 | === modified file 'openlp/core/common/openlpmixin.py' |
2 | --- openlp/core/common/openlpmixin.py 2016-05-14 04:24:46 +0000 |
3 | +++ openlp/core/common/openlpmixin.py 2016-09-09 21:59:44 +0000 |
4 | @@ -71,6 +71,12 @@ |
5 | """ |
6 | self.logger.info(message) |
7 | |
8 | + def log_warning(self, message): |
9 | + """ |
10 | + Common log warning handler |
11 | + """ |
12 | + self.logger.warning(message) |
13 | + |
14 | def log_error(self, message): |
15 | """ |
16 | Common log error handler which prints the calling path |
17 | |
18 | === modified file 'openlp/plugins/bibles/bibleplugin.py' |
19 | --- openlp/plugins/bibles/bibleplugin.py 2016-08-08 18:11:32 +0000 |
20 | +++ openlp/plugins/bibles/bibleplugin.py 2016-09-09 21:59:44 +0000 |
21 | @@ -140,10 +140,10 @@ |
22 | |
23 | def uses_theme(self, theme): |
24 | """ |
25 | - Called to find out if the bible plugin is currently using a theme. Returns ``1`` if the theme is being used, |
26 | - otherwise returns ``0``. |
27 | + Called to find out if the bible plugin is currently using a theme. |
28 | |
29 | :param theme: The theme |
30 | + :return: 1 if the theme is being used, otherwise returns 0 |
31 | """ |
32 | if str(self.settings_tab.bible_theme) == theme: |
33 | return 1 |
34 | @@ -151,11 +151,11 @@ |
35 | |
36 | def rename_theme(self, old_theme, new_theme): |
37 | """ |
38 | - Rename the theme the bible plugin is using making the plugin use the |
39 | - new name. |
40 | + Rename the theme the bible plugin is using, making the plugin use the new name. |
41 | |
42 | :param old_theme: The name of the theme the plugin should stop using. Unused for this particular plugin. |
43 | :param new_theme: The new name the plugin should now use. |
44 | + :return: None |
45 | """ |
46 | self.settings_tab.bible_theme = new_theme |
47 | self.settings_tab.save() |
48 | |
49 | === modified file 'openlp/plugins/bibles/forms/bibleimportform.py' |
50 | --- openlp/plugins/bibles/forms/bibleimportform.py 2016-08-09 20:45:25 +0000 |
51 | +++ openlp/plugins/bibles/forms/bibleimportform.py 2016-09-09 21:59:44 +0000 |
52 | @@ -25,6 +25,7 @@ |
53 | import logging |
54 | import os |
55 | import urllib.error |
56 | +from lxml import etree |
57 | |
58 | from PyQt5 import QtWidgets |
59 | try: |
60 | @@ -33,14 +34,15 @@ |
61 | except: |
62 | PYSWORD_AVAILABLE = False |
63 | |
64 | -from openlp.core.common import AppLocation, Settings, UiStrings, translate, clean_filename |
65 | +from openlp.core.common import AppLocation, Settings, UiStrings, trace_error_handler, translate |
66 | +from openlp.core.common.languagemanager import get_locale_key |
67 | from openlp.core.lib.db import delete_database |
68 | +from openlp.core.lib.exceptions import ValidationError |
69 | from openlp.core.lib.ui import critical_error_message_box |
70 | from openlp.core.ui.lib.wizard import OpenLPWizard, WizardStrings |
71 | -from openlp.core.common.languagemanager import get_locale_key |
72 | -from openlp.plugins.bibles.lib.manager import BibleFormat |
73 | from openlp.plugins.bibles.lib.db import clean_filename |
74 | from openlp.plugins.bibles.lib.importers.http import CWExtract, BGExtract, BSExtract |
75 | +from openlp.plugins.bibles.lib.manager import BibleFormat |
76 | |
77 | log = logging.getLogger(__name__) |
78 | |
79 | @@ -809,16 +811,22 @@ |
80 | sword_path=self.field('sword_zip_path'), |
81 | sword_key=self.sword_zipbible_combo_box.itemData( |
82 | self.sword_zipbible_combo_box.currentIndex())) |
83 | - if importer.do_import(license_version): |
84 | - self.manager.save_meta_data(license_version, license_version, license_copyright, license_permissions) |
85 | - self.manager.reload_bibles() |
86 | - if bible_type == BibleFormat.WebDownload: |
87 | - self.progress_label.setText( |
88 | - translate('BiblesPlugin.ImportWizardForm', 'Registered Bible. Please note, that verses will be ' |
89 | - 'downloaded on demand and thus an internet connection is required.')) |
90 | - else: |
91 | - self.progress_label.setText(WizardStrings.FinishedImport) |
92 | - else: |
93 | - self.progress_label.setText(translate('BiblesPlugin.ImportWizardForm', 'Your Bible import failed.')) |
94 | - del self.manager.db_cache[importer.name] |
95 | - delete_database(self.plugin.settings_section, importer.file) |
96 | + |
97 | + try: |
98 | + if importer.do_import(license_version) and not importer.stop_import_flag: |
99 | + self.manager.save_meta_data(license_version, license_version, license_copyright, license_permissions) |
100 | + self.manager.reload_bibles() |
101 | + if bible_type == BibleFormat.WebDownload: |
102 | + self.progress_label.setText( |
103 | + translate('BiblesPlugin.ImportWizardForm', 'Registered Bible. Please note, that verses will be ' |
104 | + 'downloaded on demand and thus an internet connection is required.')) |
105 | + else: |
106 | + self.progress_label.setText(WizardStrings.FinishedImport) |
107 | + return |
108 | + except (AttributeError, ValidationError, etree.XMLSyntaxError): |
109 | + log.exception('Importing bible failed') |
110 | + trace_error_handler(log) |
111 | + |
112 | + self.progress_label.setText(translate('BiblesPlugin.ImportWizardForm', 'Your Bible import failed.')) |
113 | + del self.manager.db_cache[importer.name] |
114 | + delete_database(self.plugin.settings_section, importer.file) |
115 | |
116 | === modified file 'openlp/plugins/bibles/lib/__init__.py' |
117 | --- openlp/plugins/bibles/lib/__init__.py 2016-05-05 15:41:48 +0000 |
118 | +++ openlp/plugins/bibles/lib/__init__.py 2016-09-09 21:59:44 +0000 |
119 | @@ -173,7 +173,7 @@ |
120 | |
121 | def update_reference_separators(): |
122 | """ |
123 | - Updates separators and matches for parsing and formating scripture references. |
124 | + Updates separators and matches for parsing and formatting scripture references. |
125 | """ |
126 | default_separators = [ |
127 | '|'.join([ |
128 | @@ -215,7 +215,7 @@ |
129 | # escape reserved characters |
130 | for character in '\\.^$*+?{}[]()': |
131 | source_string = source_string.replace(character, '\\' + character) |
132 | - # add various unicode alternatives |
133 | + # add various Unicode alternatives |
134 | source_string = source_string.replace('-', '(?:[-\u00AD\u2010\u2011\u2012\u2014\u2014\u2212\uFE63\uFF0D])') |
135 | source_string = source_string.replace(',', '(?:[,\u201A])') |
136 | REFERENCE_SEPARATORS['sep_{role}'.format(role=role)] = '\s*(?:{source})\s*'.format(source=source_string) |
137 | |
138 | === modified file 'openlp/plugins/bibles/lib/bibleimport.py' |
139 | --- openlp/plugins/bibles/lib/bibleimport.py 2016-08-09 19:32:29 +0000 |
140 | +++ openlp/plugins/bibles/lib/bibleimport.py 2016-09-09 21:59:44 +0000 |
141 | @@ -20,25 +20,84 @@ |
142 | # Temple Place, Suite 330, Boston, MA 02111-1307 USA # |
143 | ############################################################################### |
144 | |
145 | -import logging |
146 | - |
147 | from lxml import etree, objectify |
148 | +from zipfile import is_zipfile |
149 | |
150 | -from openlp.core.common import OpenLPMixin, languages |
151 | +from openlp.core.common import OpenLPMixin, Registry, RegistryProperties, languages, translate |
152 | from openlp.core.lib import ValidationError |
153 | -from openlp.plugins.bibles.lib.db import BibleDB, BiblesResourcesDB |
154 | - |
155 | -log = logging.getLogger(__name__) |
156 | - |
157 | - |
158 | -class BibleImport(OpenLPMixin, BibleDB): |
159 | +from openlp.core.lib.ui import critical_error_message_box |
160 | +from openlp.plugins.bibles.lib.db import AlternativeBookNamesDB, BibleDB, BiblesResourcesDB |
161 | + |
162 | + |
163 | +class BibleImport(OpenLPMixin, RegistryProperties, BibleDB): |
164 | """ |
165 | Helper class to import bibles from a third party source into OpenLP |
166 | """ |
167 | - # TODO: Test |
168 | def __init__(self, *args, **kwargs): |
169 | super().__init__(*args, **kwargs) |
170 | self.filename = kwargs['filename'] if 'filename' in kwargs else None |
171 | + self.wizard = None |
172 | + self.stop_import_flag = False |
173 | + Registry().register_function('openlp_stop_wizard', self.stop_import) |
174 | + |
175 | + @staticmethod |
176 | + def is_compressed(file): |
177 | + """ |
178 | + Check if the supplied file is compressed |
179 | + |
180 | + :param file: A path to the file to check |
181 | + """ |
182 | + if is_zipfile(file): |
183 | + critical_error_message_box( |
184 | + message=translate('BiblesPlugin.BibleImport', |
185 | + 'The file "{file}" you supplied is compressed. You must decompress it before import.' |
186 | + ).format(file=file)) |
187 | + return True |
188 | + return False |
189 | + |
190 | + def get_book_ref_id_by_name(self, book, maxbooks=66, language_id=None): |
191 | + """ |
192 | + Find the book id from the name or abbreviation of the book. If it doesn't currently exist, ask the user. |
193 | + |
194 | + :param book: The name or abbreviation of the book |
195 | + :param maxbooks: The number of books in the bible |
196 | + :param language_id: The language_id of the bible |
197 | + :return: The id of the bible, or None |
198 | + """ |
199 | + self.log_debug('BibleDB.get_book_ref_id_by_name:("{book}", "{lang}")'.format(book=book, lang=language_id)) |
200 | + book_temp = BiblesResourcesDB.get_book(book, True) |
201 | + if book_temp: |
202 | + return book_temp['id'] |
203 | + book_id = BiblesResourcesDB.get_alternative_book_name(book) |
204 | + if book_id: |
205 | + return book_id |
206 | + book_id = AlternativeBookNamesDB.get_book_reference_id(book) |
207 | + if book_id: |
208 | + return book_id |
209 | + from openlp.plugins.bibles.forms import BookNameForm |
210 | + book_name = BookNameForm(self.wizard) |
211 | + if book_name.exec(book, self.get_books(), maxbooks) and book_name.book_id: |
212 | + AlternativeBookNamesDB.create_alternative_book_name(book, book_name.book_id, language_id) |
213 | + return book_name.book_id |
214 | + |
215 | + def get_language(self, bible_name=None): |
216 | + """ |
217 | + If no language is given it calls a dialog window where the user could select the bible language. |
218 | + Return the language id of a bible. |
219 | + |
220 | + :param bible_name: The language the bible is. |
221 | + """ |
222 | + self.log_debug('BibleImpoer.get_language()') |
223 | + from openlp.plugins.bibles.forms import LanguageForm |
224 | + language_id = None |
225 | + language_form = LanguageForm(self.wizard) |
226 | + if language_form.exec(bible_name): |
227 | + combo_box = language_form.language_combo_box |
228 | + language_id = combo_box.itemData(combo_box.currentIndex()) |
229 | + if not language_id: |
230 | + return None |
231 | + self.save_meta('language_id', language_id) |
232 | + return language_id |
233 | |
234 | def get_language_id(self, file_language=None, bible_name=None): |
235 | """ |
236 | @@ -58,8 +117,8 @@ |
237 | language_id = self.get_language(bible_name) |
238 | if not language_id: |
239 | # User cancelled get_language dialog |
240 | - log.error('Language detection failed when importing from "{name}". User aborted language selection.' |
241 | - .format(name=bible_name)) |
242 | + self.log_error('Language detection failed when importing from "{name}". User aborted language selection.' |
243 | + .format(name=bible_name)) |
244 | return None |
245 | self.save_meta('language_id', language_id) |
246 | return language_id |
247 | @@ -77,7 +136,7 @@ |
248 | if name: |
249 | book_ref_id = self.get_book_ref_id_by_name(name, no_of_books, language_id) |
250 | else: |
251 | - log.debug('No book name supplied. Falling back to guess_id') |
252 | + self.log_debug('No book name supplied. Falling back to guess_id') |
253 | book_ref_id = guess_id |
254 | if not book_ref_id: |
255 | raise ValidationError(msg='Could not resolve book_ref_id in "{}"'.format(self.filename)) |
256 | @@ -87,8 +146,7 @@ |
257 | 'importing {file}'.format(book_ref=book_ref_id, file=self.filename)) |
258 | return self.create_book(name, book_ref_id, book_details['testament_id']) |
259 | |
260 | - @staticmethod |
261 | - def parse_xml(filename, use_objectify=False, elements=None, tags=None): |
262 | + def parse_xml(self, filename, use_objectify=False, elements=None, tags=None): |
263 | """ |
264 | Parse and clean the supplied file by removing any elements or tags we don't use. |
265 | :param filename: The filename of the xml file to parse. Str |
266 | @@ -97,17 +155,80 @@ |
267 | :param tags: A tuple of element names (Str) to remove, preserving their content. |
268 | :return: The root element of the xml document |
269 | """ |
270 | - with open(filename, 'rb') as import_file: |
271 | - # NOTE: We don't need to do any of the normal encoding detection here, because lxml does it's own encoding |
272 | - # detection, and the two mechanisms together interfere with each other. |
273 | - if not use_objectify: |
274 | - tree = etree.parse(import_file, parser=etree.XMLParser(recover=True)) |
275 | - else: |
276 | - tree = objectify.parse(import_file, parser=objectify.makeparser(recover=True)) |
277 | - if elements: |
278 | - # Strip tags we don't use - remove content |
279 | - etree.strip_elements(tree, elements, with_tail=False) |
280 | - if tags: |
281 | - # Strip tags we don't use - keep content |
282 | - etree.strip_tags(tree, tags) |
283 | - return tree.getroot() |
284 | + try: |
285 | + with open(filename, 'rb') as import_file: |
286 | + # NOTE: We don't need to do any of the normal encoding detection here, because lxml does it's own |
287 | + # encoding detection, and the two mechanisms together interfere with each other. |
288 | + if not use_objectify: |
289 | + tree = etree.parse(import_file, parser=etree.XMLParser(recover=True)) |
290 | + else: |
291 | + tree = objectify.parse(import_file, parser=objectify.makeparser(recover=True)) |
292 | + if elements or tags: |
293 | + self.wizard.increment_progress_bar( |
294 | + translate('BiblesPlugin.OsisImport', 'Removing unused tags (this may take a few minutes)...')) |
295 | + if elements: |
296 | + # Strip tags we don't use - remove content |
297 | + etree.strip_elements(tree, elements, with_tail=False) |
298 | + if tags: |
299 | + # Strip tags we don't use - keep content |
300 | + etree.strip_tags(tree, tags) |
301 | + return tree.getroot() |
302 | + except OSError as e: |
303 | + self.log_exception('Opening {file_name} failed.'.format(file_name=e.filename)) |
304 | + critical_error_message_box( |
305 | + title='An Error Occured When Opening A File', |
306 | + message='The following error occurred when trying to open\n{file_name}:\n\n{error}' |
307 | + .format(file_name=e.filename, error=e.strerror)) |
308 | + return None |
309 | + |
310 | + def register(self, wizard): |
311 | + """ |
312 | + This method basically just initialises the database. It is called from the Bible Manager when a Bible is |
313 | + imported. Descendant classes may want to override this method to supply their own custom |
314 | + initialisation as well. |
315 | + |
316 | + :param wizard: The actual Qt wizard form. |
317 | + """ |
318 | + self.wizard = wizard |
319 | + return self.name |
320 | + |
321 | + def set_current_chapter(self, book_name, chapter_name): |
322 | + self.wizard.increment_progress_bar(translate('BiblesPlugin.OsisImport', 'Importing {book} {chapter}...') |
323 | + .format(book=book_name, chapter=chapter_name)) |
324 | + |
325 | + def stop_import(self): |
326 | + """ |
327 | + Stops the import of the Bible. |
328 | + """ |
329 | + self.log_debug('Stopping import') |
330 | + self.stop_import_flag = True |
331 | + |
332 | + def validate_xml_file(self, filename, tag): |
333 | + """ |
334 | + Validate the supplied file |
335 | + |
336 | + :param filename: The supplied file |
337 | + :param tag: The expected root tag type |
338 | + :return: True if valid. ValidationError is raised otherwise. |
339 | + """ |
340 | + if BibleImport.is_compressed(filename): |
341 | + raise ValidationError(msg='Compressed file') |
342 | + bible = self.parse_xml(filename, use_objectify=True) |
343 | + if bible is None: |
344 | + raise ValidationError(msg='Error when opening file') |
345 | + root_tag = bible.tag.lower() |
346 | + bible_type = translate('BiblesPlugin.BibleImport', 'unknown type of', |
347 | + 'This looks like an unknown type of XML bible.') |
348 | + if root_tag == tag: |
349 | + return True |
350 | + elif root_tag == 'bible': |
351 | + bible_type = "OpenSong" |
352 | + elif root_tag == '{http://www.bibletechnologies.net/2003/osis/namespace}osis': |
353 | + bible_type = 'OSIS' |
354 | + elif root_tag == 'xmlbible': |
355 | + bible_type = 'Zefania' |
356 | + critical_error_message_box( |
357 | + message=translate('BiblesPlugin.BibleImport', |
358 | + 'Incorrect Bible file type supplied. This looks like an {bible_type} XML bible.' |
359 | + .format(bible_type=bible_type))) |
360 | + raise ValidationError(msg='Invalid xml.') |
361 | |
362 | === modified file 'openlp/plugins/bibles/lib/db.py' |
363 | --- openlp/plugins/bibles/lib/db.py 2016-08-07 10:15:43 +0000 |
364 | +++ openlp/plugins/bibles/lib/db.py 2016-09-09 21:59:44 +0000 |
365 | @@ -33,7 +33,7 @@ |
366 | from sqlalchemy.orm import class_mapper, mapper, relation |
367 | from sqlalchemy.orm.exc import UnmappedClassError |
368 | |
369 | -from openlp.core.common import Registry, RegistryProperties, AppLocation, translate, clean_filename |
370 | +from openlp.core.common import AppLocation, translate, clean_filename |
371 | from openlp.core.lib.db import BaseModel, init_db, Manager |
372 | from openlp.core.lib.ui import critical_error_message_box |
373 | from openlp.plugins.bibles.lib import upgrade |
374 | @@ -106,7 +106,7 @@ |
375 | return session |
376 | |
377 | |
378 | -class BibleDB(Manager, RegistryProperties): |
379 | +class BibleDB(Manager): |
380 | """ |
381 | This class represents a database-bound Bible. It is used as a base class for all the custom importers, so that |
382 | the can implement their own import methods, but benefit from the database methods in here via inheritance, |
383 | @@ -140,7 +140,6 @@ |
384 | raise KeyError('Missing keyword argument "path".') |
385 | if 'name' not in kwargs and 'file' not in kwargs: |
386 | raise KeyError('Missing keyword argument "name" or "file".') |
387 | - self.stop_import_flag = False |
388 | if 'name' in kwargs: |
389 | self.name = kwargs['name'] |
390 | if not isinstance(self.name, str): |
391 | @@ -153,15 +152,6 @@ |
392 | self.get_name() |
393 | if 'path' in kwargs: |
394 | self.path = kwargs['path'] |
395 | - self.wizard = None |
396 | - Registry().register_function('openlp_stop_wizard', self.stop_import) |
397 | - |
398 | - def stop_import(self): |
399 | - """ |
400 | - Stops the import of the Bible. |
401 | - """ |
402 | - log.debug('Stopping import') |
403 | - self.stop_import_flag = True |
404 | |
405 | def get_name(self): |
406 | """ |
407 | @@ -171,17 +161,6 @@ |
408 | self.name = version_name.value if version_name else None |
409 | return self.name |
410 | |
411 | - def register(self, wizard): |
412 | - """ |
413 | - This method basically just initialises the database. It is called from the Bible Manager when a Bible is |
414 | - imported. Descendant classes may want to override this method to supply their own custom |
415 | - initialisation as well. |
416 | - |
417 | - :param wizard: The actual Qt wizard form. |
418 | - """ |
419 | - self.wizard = wizard |
420 | - return self.name |
421 | - |
422 | def create_book(self, name, bk_ref_id, testament=1): |
423 | """ |
424 | Add a book to the database. |
425 | @@ -306,26 +285,6 @@ |
426 | log.debug('BibleDB.get_book_by_book_ref_id("{ref}")'.format(ref=ref_id)) |
427 | return self.get_object_filtered(Book, Book.book_reference_id.like(ref_id)) |
428 | |
429 | - def get_book_ref_id_by_name(self, book, maxbooks, language_id=None): |
430 | - log.debug('BibleDB.get_book_ref_id_by_name:("{book}", "{lang}")'.format(book=book, lang=language_id)) |
431 | - book_id = None |
432 | - if BiblesResourcesDB.get_book(book, True): |
433 | - book_temp = BiblesResourcesDB.get_book(book, True) |
434 | - book_id = book_temp['id'] |
435 | - elif BiblesResourcesDB.get_alternative_book_name(book): |
436 | - book_id = BiblesResourcesDB.get_alternative_book_name(book) |
437 | - elif AlternativeBookNamesDB.get_book_reference_id(book): |
438 | - book_id = AlternativeBookNamesDB.get_book_reference_id(book) |
439 | - else: |
440 | - from openlp.plugins.bibles.forms import BookNameForm |
441 | - book_name = BookNameForm(self.wizard) |
442 | - if book_name.exec(book, self.get_books(), maxbooks): |
443 | - book_id = book_name.book_id |
444 | - if book_id: |
445 | - AlternativeBookNamesDB.create_alternative_book_name( |
446 | - book, book_id, language_id) |
447 | - return book_id |
448 | - |
449 | def get_book_ref_id_by_localised_name(self, book, language_selection): |
450 | """ |
451 | Return the id of a named book. |
452 | @@ -462,25 +421,6 @@ |
453 | return 0 |
454 | return count |
455 | |
456 | - def get_language(self, bible_name=None): |
457 | - """ |
458 | - If no language is given it calls a dialog window where the user could select the bible language. |
459 | - Return the language id of a bible. |
460 | - |
461 | - :param bible_name: The language the bible is. |
462 | - """ |
463 | - log.debug('BibleDB.get_language()') |
464 | - from openlp.plugins.bibles.forms import LanguageForm |
465 | - language_id = None |
466 | - language_form = LanguageForm(self.wizard) |
467 | - if language_form.exec(bible_name): |
468 | - combo_box = language_form.language_combo_box |
469 | - language_id = combo_box.itemData(combo_box.currentIndex()) |
470 | - if not language_id: |
471 | - return None |
472 | - self.save_meta('language_id', language_id) |
473 | - return language_id |
474 | - |
475 | def dump_bible(self): |
476 | """ |
477 | Utility debugging method to dump the contents of a bible. |
478 | |
479 | === modified file 'openlp/plugins/bibles/lib/importers/csvbible.py' |
480 | --- openlp/plugins/bibles/lib/importers/csvbible.py 2016-08-09 20:45:25 +0000 |
481 | +++ openlp/plugins/bibles/lib/importers/csvbible.py 2016-09-09 21:59:44 +0000 |
482 | @@ -50,7 +50,6 @@ |
483 | All CSV files are expected to use a comma (',') as the delimiter and double quotes ('"') as the quote symbol. |
484 | """ |
485 | import csv |
486 | -import logging |
487 | from collections import namedtuple |
488 | |
489 | from openlp.core.common import get_file_encoding, translate |
490 | @@ -58,8 +57,6 @@ |
491 | from openlp.plugins.bibles.lib.bibleimport import BibleImport |
492 | |
493 | |
494 | -log = logging.getLogger(__name__) |
495 | - |
496 | Book = namedtuple('Book', 'id, testament_id, name, abbreviation') |
497 | Verse = namedtuple('Verse', 'book_id_name, chapter_number, number, text') |
498 | |
499 | @@ -68,15 +65,13 @@ |
500 | """ |
501 | This class provides a specialisation for importing of CSV Bibles. |
502 | """ |
503 | - log.info('CSVBible loaded') |
504 | - |
505 | def __init__(self, *args, **kwargs): |
506 | """ |
507 | Loads a Bible from a set of CSV files. This class assumes the files contain all the information and a clean |
508 | bible is being loaded. |
509 | """ |
510 | - log.info(self.__class__.__name__) |
511 | super().__init__(*args, **kwargs) |
512 | + self.log_info(self.__class__.__name__) |
513 | self.books_file = kwargs['booksfile'] |
514 | self.verses_file = kwargs['versefile'] |
515 | |
516 | @@ -123,12 +118,11 @@ |
517 | number_of_books = len(books) |
518 | for book in books: |
519 | if self.stop_import_flag: |
520 | - return None |
521 | + break |
522 | self.wizard.increment_progress_bar( |
523 | translate('BiblesPlugin.CSVBible', 'Importing books... {book}').format(book=book.name)) |
524 | self.find_and_create_book(book.name, number_of_books, self.language_id) |
525 | book_list.update({int(book.id): book.name}) |
526 | - self.application.process_events() |
527 | return book_list |
528 | |
529 | def process_verses(self, verses, books): |
530 | @@ -142,7 +136,7 @@ |
531 | book_ptr = None |
532 | for verse in verses: |
533 | if self.stop_import_flag: |
534 | - return None |
535 | + break |
536 | verse_book = self.get_book_name(verse.book_id_name, books) |
537 | if book_ptr != verse_book: |
538 | book = self.get_book(verse_book) |
539 | @@ -151,9 +145,7 @@ |
540 | translate('BiblesPlugin.CSVBible', 'Importing verses from {book}...', |
541 | 'Importing verses from <book name>...').format(book=book.name)) |
542 | self.session.commit() |
543 | - self.create_verse(book.id, verse.chapter_number, verse.number, verse.text) |
544 | - self.wizard.increment_progress_bar(translate('BiblesPlugin.CSVBible', 'Importing verses... done.')) |
545 | - self.application.process_events() |
546 | + self.create_verse(book.id, int(verse.chapter_number), int(verse.number), verse.text) |
547 | self.session.commit() |
548 | |
549 | def do_import(self, bible_name=None): |
550 | @@ -163,24 +155,16 @@ |
551 | :param bible_name: Optional name of the bible being imported. Str or None |
552 | :return: True if the import was successful, False if it failed or was cancelled |
553 | """ |
554 | - try: |
555 | - self.language_id = self.get_language(bible_name) |
556 | - if not self.language_id: |
557 | - raise ValidationError(msg='Invalid language selected') |
558 | - books = self.parse_csv_file(self.books_file, Book) |
559 | - self.wizard.progress_bar.setValue(0) |
560 | - self.wizard.progress_bar.setMinimum(0) |
561 | - self.wizard.progress_bar.setMaximum(len(books)) |
562 | - book_list = self.process_books(books) |
563 | - if self.stop_import_flag: |
564 | - return False |
565 | - verses = self.parse_csv_file(self.verses_file, Verse) |
566 | - self.wizard.progress_bar.setValue(0) |
567 | - self.wizard.progress_bar.setMaximum(len(books) + 1) |
568 | - self.process_verses(verses, book_list) |
569 | - if self.stop_import_flag: |
570 | - return False |
571 | - except ValidationError: |
572 | - log.exception('Could not import CSV bible') |
573 | + self.language_id = self.get_language(bible_name) |
574 | + if not self.language_id: |
575 | return False |
576 | + books = self.parse_csv_file(self.books_file, Book) |
577 | + self.wizard.progress_bar.setValue(0) |
578 | + self.wizard.progress_bar.setMinimum(0) |
579 | + self.wizard.progress_bar.setMaximum(len(books)) |
580 | + book_list = self.process_books(books) |
581 | + verses = self.parse_csv_file(self.verses_file, Verse) |
582 | + self.wizard.progress_bar.setValue(0) |
583 | + self.wizard.progress_bar.setMaximum(len(books) + 1) |
584 | + self.process_verses(verses, book_list) |
585 | return True |
586 | |
587 | === modified file 'openlp/plugins/bibles/lib/importers/opensong.py' |
588 | --- openlp/plugins/bibles/lib/importers/opensong.py 2016-08-09 20:45:25 +0000 |
589 | +++ openlp/plugins/bibles/lib/importers/opensong.py 2016-09-09 21:59:44 +0000 |
590 | @@ -20,109 +20,126 @@ |
591 | # Temple Place, Suite 330, Boston, MA 02111-1307 USA # |
592 | ############################################################################### |
593 | |
594 | -import logging |
595 | -from lxml import etree, objectify |
596 | - |
597 | -from openlp.core.common import translate, trace_error_handler |
598 | -from openlp.core.lib.ui import critical_error_message_box |
599 | from openlp.plugins.bibles.lib.bibleimport import BibleImport |
600 | -from openlp.plugins.bibles.lib.db import BibleDB, BiblesResourcesDB |
601 | - |
602 | - |
603 | -log = logging.getLogger(__name__) |
604 | + |
605 | + |
606 | +def get_text(element): |
607 | + """ |
608 | + Recursively get all text in an objectify element and its child elements. |
609 | + |
610 | + :param element: An objectify element to get the text from |
611 | + :return: The text content of the element (str) |
612 | + """ |
613 | + verse_text = '' |
614 | + if element.text: |
615 | + verse_text = element.text |
616 | + for sub_element in element.iterchildren(): |
617 | + verse_text += get_text(sub_element) |
618 | + if element.tail: |
619 | + verse_text += element.tail |
620 | + return verse_text |
621 | + |
622 | + |
623 | +def parse_chapter_number(number, previous_number): |
624 | + """ |
625 | + Parse the chapter number |
626 | + |
627 | + :param number: The raw data from the xml |
628 | + :param previous_number: The previous chapter number |
629 | + :return: Number of current chapter. (Int) |
630 | + """ |
631 | + if number: |
632 | + return int(number.split()[-1]) |
633 | + return previous_number + 1 |
634 | |
635 | |
636 | class OpenSongBible(BibleImport): |
637 | """ |
638 | OpenSong Bible format importer class. This class is used to import Bibles from OpenSong's XML format. |
639 | """ |
640 | - def get_text(self, element): |
641 | - """ |
642 | - Recursively get all text in an objectify element and its child elements. |
643 | - |
644 | - :param element: An objectify element to get the text from |
645 | - """ |
646 | - verse_text = '' |
647 | - if element.text: |
648 | - verse_text = element.text |
649 | - for sub_element in element.iterchildren(): |
650 | - verse_text += self.get_text(sub_element) |
651 | - if element.tail: |
652 | - verse_text += element.tail |
653 | - return verse_text |
654 | + |
655 | + def parse_verse_number(self, number, previous_number): |
656 | + """ |
657 | + Parse the verse number retrieved from the xml |
658 | + |
659 | + :param number: The raw data from the xml |
660 | + :param previous_number: The previous verse number |
661 | + :return: Number of current verse. (Int) |
662 | + """ |
663 | + if not number: |
664 | + return previous_number + 1 |
665 | + try: |
666 | + return int(number) |
667 | + except ValueError: |
668 | + verse_parts = number.split('-') |
669 | + if len(verse_parts) > 1: |
670 | + number = int(verse_parts[0]) |
671 | + return number |
672 | + except TypeError: |
673 | + self.log_warning('Illegal verse number: {verse_no}'.format(verse_no=str(number))) |
674 | + return previous_number + 1 |
675 | + |
676 | + def process_books(self, books): |
677 | + """ |
678 | + Extract and create the books from the objectified xml |
679 | + |
680 | + :param books: Objectified xml |
681 | + :return: None |
682 | + """ |
683 | + for book in books: |
684 | + if self.stop_import_flag: |
685 | + break |
686 | + db_book = self.find_and_create_book(str(book.attrib['n']), len(books), self.language_id) |
687 | + self.process_chapters(db_book, book.c) |
688 | + self.session.commit() |
689 | + |
690 | + def process_chapters(self, book, chapters): |
691 | + """ |
692 | + Extract and create the chapters from the objectified xml for the book `book` |
693 | + |
694 | + :param book: A database Book object to add the chapters to |
695 | + :param chapters: Objectified xml containing chapters |
696 | + :return: None |
697 | + """ |
698 | + chapter_number = 0 |
699 | + for chapter in chapters: |
700 | + if self.stop_import_flag: |
701 | + break |
702 | + chapter_number = parse_chapter_number(chapter.attrib['n'], chapter_number) |
703 | + self.set_current_chapter(book.name, chapter_number) |
704 | + self.process_verses(book, chapter_number, chapter.v) |
705 | + |
706 | + def process_verses(self, book, chapter_number, verses): |
707 | + """ |
708 | + Extract and create the verses from the objectified xml |
709 | + |
710 | + :param book: A database Book object |
711 | + :param chapter_number: The chapter number to add the verses to (int) |
712 | + :param verses: Objectified xml containing verses |
713 | + :return: None |
714 | + """ |
715 | + verse_number = 0 |
716 | + for verse in verses: |
717 | + if self.stop_import_flag: |
718 | + break |
719 | + verse_number = self.parse_verse_number(verse.attrib['n'], verse_number) |
720 | + self.create_verse(book.id, chapter_number, verse_number, get_text(verse)) |
721 | |
722 | def do_import(self, bible_name=None): |
723 | """ |
724 | - Loads a Bible from file. |
725 | + Loads an Open Song Bible from a file. |
726 | + |
727 | + :param bible_name: The name of the bible being imported |
728 | + :return: True if import completed, False if import was unsuccessful |
729 | """ |
730 | - log.debug('Starting OpenSong import from "{name}"'.format(name=self.filename)) |
731 | - success = True |
732 | - try: |
733 | - bible = self.parse_xml(self.filename, use_objectify=True) |
734 | - # Check that we're not trying to import a Zefania XML bible, it is sometimes refered to as 'OpenSong' |
735 | - if bible.tag.upper() == 'XMLBIBLE': |
736 | - critical_error_message_box( |
737 | - message=translate('BiblesPlugin.OpenSongImport', |
738 | - 'Incorrect Bible file type supplied. This looks like a Zefania XML bible, ' |
739 | - 'please use the Zefania import option.')) |
740 | - return False |
741 | - # No language info in the opensong format, so ask the user |
742 | - language_id = self.get_language_id(bible_name=self.filename) |
743 | - if not language_id: |
744 | - return False |
745 | - for book in bible.b: |
746 | - if self.stop_import_flag: |
747 | - break |
748 | - book_ref_id = self.get_book_ref_id_by_name(str(book.attrib['n']), len(bible.b), language_id) |
749 | - if not book_ref_id: |
750 | - log.error('Importing books from "{name}" failed'.format(name=self.filename)) |
751 | - return False |
752 | - book_details = BiblesResourcesDB.get_book_by_id(book_ref_id) |
753 | - db_book = self.create_book(book.attrib['n'], book_ref_id, book_details['testament_id']) |
754 | - chapter_number = 0 |
755 | - for chapter in book.c: |
756 | - if self.stop_import_flag: |
757 | - break |
758 | - number = chapter.attrib['n'] |
759 | - if number: |
760 | - chapter_number = int(number.split()[-1]) |
761 | - else: |
762 | - chapter_number += 1 |
763 | - verse_number = 0 |
764 | - for verse in chapter.v: |
765 | - if self.stop_import_flag: |
766 | - break |
767 | - number = verse.attrib['n'] |
768 | - if number: |
769 | - try: |
770 | - number = int(number) |
771 | - except ValueError: |
772 | - verse_parts = number.split('-') |
773 | - if len(verse_parts) > 1: |
774 | - number = int(verse_parts[0]) |
775 | - except TypeError: |
776 | - log.warning('Illegal verse number: {verse:d}'.format(verse=verse.attrib['n'])) |
777 | - verse_number = number |
778 | - else: |
779 | - verse_number += 1 |
780 | - self.create_verse(db_book.id, chapter_number, verse_number, self.get_text(verse)) |
781 | - self.wizard.increment_progress_bar(translate('BiblesPlugin.Opensong', |
782 | - 'Importing {name} {chapter}...' |
783 | - ).format(name=db_book.name, chapter=chapter_number)) |
784 | - self.session.commit() |
785 | - self.application.process_events() |
786 | - except etree.XMLSyntaxError as inst: |
787 | - trace_error_handler(log) |
788 | - critical_error_message_box( |
789 | - message=translate('BiblesPlugin.OpenSongImport', |
790 | - 'Incorrect Bible file type supplied. OpenSong Bibles may be ' |
791 | - 'compressed. You must decompress them before import.')) |
792 | - log.exception(inst) |
793 | - success = False |
794 | - except (IOError, AttributeError): |
795 | - log.exception('Loading Bible from OpenSong file failed') |
796 | - success = False |
797 | - if self.stop_import_flag: |
798 | - return False |
799 | - else: |
800 | - return success |
801 | + self.log_debug('Starting OpenSong import from "{name}"'.format(name=self.filename)) |
802 | + self.validate_xml_file(self.filename, 'bible') |
803 | + bible = self.parse_xml(self.filename, use_objectify=True) |
804 | + if bible is None: |
805 | + return False |
806 | + # No language info in the opensong format, so ask the user |
807 | + self.language_id = self.get_language_id(bible_name=self.filename) |
808 | + if not self.language_id: |
809 | + return False |
810 | + self.process_books(bible.b) |
811 | + return True |
812 | |
813 | === modified file 'openlp/plugins/bibles/lib/importers/osis.py' |
814 | --- openlp/plugins/bibles/lib/importers/osis.py 2016-08-10 19:08:09 +0000 |
815 | +++ openlp/plugins/bibles/lib/importers/osis.py 2016-09-09 21:59:44 +0000 |
816 | @@ -20,15 +20,9 @@ |
817 | # Temple Place, Suite 330, Boston, MA 02111-1307 USA # |
818 | ############################################################################### |
819 | |
820 | -import logging |
821 | from lxml import etree |
822 | |
823 | -from openlp.core.common import translate, trace_error_handler |
824 | -from openlp.core.lib.ui import critical_error_message_box |
825 | from openlp.plugins.bibles.lib.bibleimport import BibleImport |
826 | -from openlp.plugins.bibles.lib.db import BiblesResourcesDB |
827 | - |
828 | -log = logging.getLogger(__name__) |
829 | |
830 | NS = {'ns': 'http://www.bibletechnologies.net/2003/OSIS/namespace'} |
831 | # Tags we don't use and can remove the content |
832 | @@ -74,104 +68,106 @@ |
833 | '{http://www.bibletechnologies.net/2003/OSIS/namespace}caption' |
834 | ) |
835 | |
836 | - |
837 | -def replacement(match): |
838 | - return match.group(2).upper() |
839 | +# Precompile a few xpath-querys |
840 | +verse_in_chapter = etree.XPath('//ns:chapter[1]/ns:verse', namespaces=NS) |
841 | +text_in_verse = etree.XPath('//ns:verse[1]/text()', namespaces=NS) |
842 | |
843 | |
844 | class OSISBible(BibleImport): |
845 | """ |
846 | `OSIS <http://www.bibletechnologies.net/>`_ Bible format importer class. |
847 | """ |
848 | + def process_books(self, bible_data): |
849 | + """ |
850 | + Extract and create the bible books from the parsed xml |
851 | + |
852 | + :param bible_data: parsed xml |
853 | + :return: None |
854 | + """ |
855 | + # Find books in the bible |
856 | + bible_books = bible_data.xpath("//ns:div[@type='book']", namespaces=NS) |
857 | + no_of_books = len(bible_books) |
858 | + for book in bible_books: |
859 | + if self.stop_import_flag: |
860 | + break |
861 | + # Remove div-tags in the book |
862 | + etree.strip_tags(book, '{http://www.bibletechnologies.net/2003/OSIS/namespace}div') |
863 | + db_book = self.find_and_create_book(book.get('osisID'), no_of_books, self.language_id) |
864 | + self.process_chapters(db_book, book) |
865 | + self.session.commit() |
866 | + |
867 | + def process_chapters(self, book, chapters): |
868 | + """ |
869 | + Extract the chapters, and do some initial processing of the verses |
870 | + |
871 | + :param book: An OpenLP bible database book object |
872 | + :param chapters: parsed chapters |
873 | + :return: None |
874 | + """ |
875 | + # Find out if chapter-tags contains the verses, or if it is used as milestone/anchor |
876 | + if verse_in_chapter(chapters): |
877 | + # The chapter tags contains the verses |
878 | + for chapter in chapters: |
879 | + chapter_number = int(chapter.get("osisID").split('.')[1]) |
880 | + self.set_current_chapter(book.name, chapter_number) |
881 | + # Find out if verse-tags contains the text, or if it is used as milestone/anchor |
882 | + if not text_in_verse(chapter): |
883 | + # verse-tags are used as milestone |
884 | + for verse in chapter: |
885 | + # If this tag marks the start of a verse, the verse text is between this tag and |
886 | + # the next tag, which the "tail" attribute gives us. |
887 | + self.process_verse(book, chapter_number, verse, use_milestones=True) |
888 | + else: |
889 | + # Verse-tags contains the text |
890 | + for verse in chapter: |
891 | + self.process_verse(book, chapter_number, verse) |
892 | + else: |
893 | + # The chapter tags is used as milestones. For now we assume verses is also milestones |
894 | + chapter_number = 0 |
895 | + for element in chapters: |
896 | + if element.tag == '{http://www.bibletechnologies.net/2003/OSIS/namespace}chapter' \ |
897 | + and element.get('sID'): |
898 | + chapter_number = int(element.get("osisID").split('.')[1]) |
899 | + self.set_current_chapter(book.name, chapter_number) |
900 | + elif element.tag == '{http://www.bibletechnologies.net/2003/OSIS/namespace}verse': |
901 | + # If this tag marks the start of a verse, the verse text is between this tag and |
902 | + # the next tag, which the "tail" attribute gives us. |
903 | + self.process_verse(book, chapter_number, element, use_milestones=True) |
904 | + |
905 | + def process_verse(self, book, chapter_number, element, use_milestones=False): |
906 | + """ |
907 | + Process a verse element |
908 | + :param book: A database Book object |
909 | + :param chapter_number: The chapter number to add the verses to (int) |
910 | + :param element: The verse element to process. (etree element type) |
911 | + :param use_milestones: set to True to process a 'milestone' verse. Defaults to False |
912 | + :return: None |
913 | + """ |
914 | + osis_id = element.get("osisID") |
915 | + if not osis_id: |
916 | + return None |
917 | + verse_number = int(osis_id.split('.')[2]) |
918 | + verse_text = '' |
919 | + if use_milestones and element.get('sID'): |
920 | + verse_text = element.tail |
921 | + elif not use_milestones: |
922 | + verse_text = element.text |
923 | + if verse_text: |
924 | + self.create_verse(book.id, chapter_number, verse_number, verse_text.strip()) |
925 | + |
926 | def do_import(self, bible_name=None): |
927 | """ |
928 | Loads a Bible from file. |
929 | """ |
930 | - log.debug('Starting OSIS import from "{name}"'.format(name=self.filename)) |
931 | - success = True |
932 | - try: |
933 | - self.wizard.increment_progress_bar(translate('BiblesPlugin.OsisImport', |
934 | - 'Removing unused tags (this may take a few minutes)...')) |
935 | - osis_bible_tree = self.parse_xml(self.filename, elements=REMOVABLE_ELEMENTS, tags=REMOVABLE_TAGS) |
936 | - # Find bible language] |
937 | - language = osis_bible_tree.xpath("//ns:osisText/@xml:lang", namespaces=NS) |
938 | - language_id = self.get_language_id(language[0] if language else None, bible_name=self.filename) |
939 | - if not language_id: |
940 | - return False |
941 | - num_books = int(osis_bible_tree.xpath("count(//ns:div[@type='book'])", namespaces=NS)) |
942 | - # Precompile a few xpath-querys |
943 | - verse_in_chapter = etree.XPath('count(//ns:chapter[1]/ns:verse)', namespaces=NS) |
944 | - text_in_verse = etree.XPath('count(//ns:verse[1]/text())', namespaces=NS) |
945 | - # Find books in the bible |
946 | - bible_books = osis_bible_tree.xpath("//ns:div[@type='book']", namespaces=NS) |
947 | - for book in bible_books: |
948 | - if self.stop_import_flag: |
949 | - break |
950 | - # Remove div-tags in the book |
951 | - etree.strip_tags(book, ('{http://www.bibletechnologies.net/2003/OSIS/namespace}div')) |
952 | - book_ref_id = self.get_book_ref_id_by_name(book.get('osisID'), num_books, language_id) |
953 | - if not book_ref_id: |
954 | - log.error('Importing books from "{name}" failed'.format(name=self.filename)) |
955 | - return False |
956 | - book_details = BiblesResourcesDB.get_book_by_id(book_ref_id) |
957 | - db_book = self.create_book(book_details['name'], book_ref_id, book_details['testament_id']) |
958 | - # Find out if chapter-tags contains the verses, or if it is used as milestone/anchor |
959 | - if int(verse_in_chapter(book)) > 0: |
960 | - # The chapter tags contains the verses |
961 | - for chapter in book: |
962 | - chapter_number = chapter.get("osisID").split('.')[1] |
963 | - # Find out if verse-tags contains the text, or if it is used as milestone/anchor |
964 | - if int(text_in_verse(chapter)) == 0: |
965 | - # verse-tags are used as milestone |
966 | - for verse in chapter: |
967 | - # If this tag marks the start of a verse, the verse text is between this tag and |
968 | - # the next tag, which the "tail" attribute gives us. |
969 | - if verse.get('sID'): |
970 | - verse_number = verse.get("osisID").split('.')[2] |
971 | - verse_text = verse.tail |
972 | - if verse_text: |
973 | - self.create_verse(db_book.id, chapter_number, verse_number, verse_text.strip()) |
974 | - else: |
975 | - # Verse-tags contains the text |
976 | - for verse in chapter: |
977 | - verse_number = verse.get("osisID").split('.')[2] |
978 | - if verse.text: |
979 | - self.create_verse(db_book.id, chapter_number, verse_number, verse.text.strip()) |
980 | - self.wizard.increment_progress_bar( |
981 | - translate('BiblesPlugin.OsisImport', 'Importing %(bookname)s %(chapter)s...') % |
982 | - {'bookname': db_book.name, 'chapter': chapter_number}) |
983 | - else: |
984 | - # The chapter tags is used as milestones. For now we assume verses is also milestones |
985 | - chapter_number = 0 |
986 | - for element in book: |
987 | - if element.tag == '{http://www.bibletechnologies.net/2003/OSIS/namespace}chapter' \ |
988 | - and element.get('sID'): |
989 | - chapter_number = element.get("osisID").split('.')[1] |
990 | - self.wizard.increment_progress_bar( |
991 | - translate('BiblesPlugin.OsisImport', 'Importing %(bookname)s %(chapter)s...') % |
992 | - {'bookname': db_book.name, 'chapter': chapter_number}) |
993 | - elif element.tag == '{http://www.bibletechnologies.net/2003/OSIS/namespace}verse' \ |
994 | - and element.get('sID'): |
995 | - # If this tag marks the start of a verse, the verse text is between this tag and |
996 | - # the next tag, which the "tail" attribute gives us. |
997 | - verse_number = element.get("osisID").split('.')[2] |
998 | - verse_text = element.tail |
999 | - if verse_text: |
1000 | - self.create_verse(db_book.id, chapter_number, verse_number, verse_text.strip()) |
1001 | - self.session.commit() |
1002 | - self.application.process_events() |
1003 | - except (ValueError, IOError): |
1004 | - log.exception('Loading bible from OSIS file failed') |
1005 | - trace_error_handler(log) |
1006 | - success = False |
1007 | - except etree.XMLSyntaxError as e: |
1008 | - log.exception('Loading bible from OSIS file failed') |
1009 | - trace_error_handler(log) |
1010 | - success = False |
1011 | - critical_error_message_box(message=translate('BiblesPlugin.OsisImport', |
1012 | - 'The file is not a valid OSIS-XML file:' |
1013 | - '\n{text}').format(text=e.msg)) |
1014 | - if self.stop_import_flag: |
1015 | - return False |
1016 | - else: |
1017 | - return success |
1018 | + self.log_debug('Starting OSIS import from "{name}"'.format(name=self.filename)) |
1019 | + self.validate_xml_file(self.filename, '{http://www.bibletechnologies.net/2003/osis/namespace}osis') |
1020 | + bible = self.parse_xml(self.filename, elements=REMOVABLE_ELEMENTS, tags=REMOVABLE_TAGS) |
1021 | + if bible is None: |
1022 | + return False |
1023 | + # Find bible language |
1024 | + language = bible.xpath("//ns:osisText/@xml:lang", namespaces=NS) |
1025 | + self.language_id = self.get_language_id(language[0] if language else None, bible_name=self.filename) |
1026 | + if not self.language_id: |
1027 | + return False |
1028 | + self.process_books(bible) |
1029 | + return True |
1030 | |
1031 | === modified file 'openlp/plugins/bibles/lib/importers/zefania.py' |
1032 | --- openlp/plugins/bibles/lib/importers/zefania.py 2016-08-09 20:45:25 +0000 |
1033 | +++ openlp/plugins/bibles/lib/importers/zefania.py 2016-09-09 21:59:44 +0000 |
1034 | @@ -54,7 +54,7 @@ |
1035 | language_id = self.get_language_id(language[0] if language else None, bible_name=self.filename) |
1036 | if not language_id: |
1037 | return False |
1038 | - num_books = int(xmlbible.xpath('count(//BIBLEBOOK)')) |
1039 | + no_of_books = int(xmlbible.xpath('count(//BIBLEBOOK)')) |
1040 | self.wizard.progress_bar.setMaximum(int(xmlbible.xpath('count(//CHAPTER)'))) |
1041 | for BIBLEBOOK in xmlbible: |
1042 | if self.stop_import_flag: |
1043 | @@ -64,7 +64,7 @@ |
1044 | if not bname and not bnumber: |
1045 | continue |
1046 | if bname: |
1047 | - book_ref_id = self.get_book_ref_id_by_name(bname, num_books, language_id) |
1048 | + book_ref_id = self.get_book_ref_id_by_name(bname, no_of_books, language_id) |
1049 | else: |
1050 | log.debug('Could not find a name, will use number, basically a guess.') |
1051 | book_ref_id = int(bnumber) |
1052 | @@ -79,7 +79,8 @@ |
1053 | chapter_number = CHAPTER.get("cnumber") |
1054 | for VERS in CHAPTER: |
1055 | verse_number = VERS.get("vnumber") |
1056 | - self.create_verse(db_book.id, chapter_number, verse_number, VERS.text.replace('<BR/>', '\n')) |
1057 | + self.create_verse( |
1058 | + db_book.id, int(chapter_number), int(verse_number), VERS.text.replace('<BR/>', '\n')) |
1059 | self.wizard.increment_progress_bar( |
1060 | translate('BiblesPlugin.Zefnia', |
1061 | 'Importing {book} {chapter}...').format(book=db_book.name, |
1062 | |
1063 | === modified file 'openlp/plugins/bibles/lib/manager.py' |
1064 | --- openlp/plugins/bibles/lib/manager.py 2016-08-12 17:26:54 +0000 |
1065 | +++ openlp/plugins/bibles/lib/manager.py 2016-09-09 21:59:44 +0000 |
1066 | @@ -23,8 +23,8 @@ |
1067 | import logging |
1068 | import os |
1069 | |
1070 | -from openlp.core.common import RegistryProperties, AppLocation, Settings, translate, delete_file, UiStrings |
1071 | -from openlp.plugins.bibles.lib import parse_reference, LanguageSelection |
1072 | +from openlp.core.common import AppLocation, OpenLPMixin, RegistryProperties, Settings, translate, delete_file, UiStrings |
1073 | +from openlp.plugins.bibles.lib import LanguageSelection, parse_reference |
1074 | from openlp.plugins.bibles.lib.db import BibleDB, BibleMeta |
1075 | from .importers.csvbible import CSVBible |
1076 | from .importers.http import HTTPBible |
1077 | @@ -88,7 +88,7 @@ |
1078 | ] |
1079 | |
1080 | |
1081 | -class BibleManager(RegistryProperties): |
1082 | +class BibleManager(OpenLPMixin, RegistryProperties): |
1083 | """ |
1084 | The Bible manager which holds and manages all the Bibles. |
1085 | """ |
1086 | |
1087 | === modified file 'openlp/plugins/bibles/lib/upgrade.py' |
1088 | --- openlp/plugins/bibles/lib/upgrade.py 2016-05-21 08:31:24 +0000 |
1089 | +++ openlp/plugins/bibles/lib/upgrade.py 2016-09-09 21:59:44 +0000 |
1090 | @@ -24,8 +24,6 @@ |
1091 | """ |
1092 | import logging |
1093 | |
1094 | -from sqlalchemy import delete, func, insert, select |
1095 | - |
1096 | log = logging.getLogger(__name__) |
1097 | __version__ = 1 |
1098 | |
1099 | @@ -35,166 +33,6 @@ |
1100 | """ |
1101 | Version 1 upgrade. |
1102 | |
1103 | - This upgrade renames a number of keys to a single naming convention. |
1104 | + This upgrade renamed a number of keys to a single naming convention. |
1105 | """ |
1106 | - metadata_table = metadata.tables['metadata'] |
1107 | - # Copy "Version" to "name" ("version" used by upgrade system) |
1108 | - try: |
1109 | - session.execute(insert(metadata_table).values( |
1110 | - key='name', |
1111 | - value=select( |
1112 | - [metadata_table.c.value], |
1113 | - metadata_table.c.key == 'Version' |
1114 | - ).as_scalar() |
1115 | - )) |
1116 | - session.execute(delete(metadata_table).where(metadata_table.c.key == 'Version')) |
1117 | - except: |
1118 | - log.exception('Exception when upgrading Version') |
1119 | - # Copy "Copyright" to "copyright" |
1120 | - try: |
1121 | - session.execute(insert(metadata_table).values( |
1122 | - key='copyright', |
1123 | - value=select( |
1124 | - [metadata_table.c.value], |
1125 | - metadata_table.c.key == 'Copyright' |
1126 | - ).as_scalar() |
1127 | - )) |
1128 | - session.execute(delete(metadata_table).where(metadata_table.c.key == 'Copyright')) |
1129 | - except: |
1130 | - log.exception('Exception when upgrading Copyright') |
1131 | - # Copy "Permissions" to "permissions" |
1132 | - try: |
1133 | - session.execute(insert(metadata_table).values( |
1134 | - key='permissions', |
1135 | - value=select( |
1136 | - [metadata_table.c.value], |
1137 | - metadata_table.c.key == 'Permissions' |
1138 | - ).as_scalar() |
1139 | - )) |
1140 | - session.execute(delete(metadata_table).where(metadata_table.c.key == 'Permissions')) |
1141 | - except: |
1142 | - log.exception('Exception when upgrading Permissions') |
1143 | - # Copy "Bookname language" to "book_name_language" |
1144 | - try: |
1145 | - value_count = session.execute( |
1146 | - select( |
1147 | - [func.count(metadata_table.c.value)], |
1148 | - metadata_table.c.key == 'Bookname language' |
1149 | - ) |
1150 | - ).scalar() |
1151 | - if value_count > 0: |
1152 | - session.execute(insert(metadata_table).values( |
1153 | - key='book_name_language', |
1154 | - value=select( |
1155 | - [metadata_table.c.value], |
1156 | - metadata_table.c.key == 'Bookname language' |
1157 | - ).as_scalar() |
1158 | - )) |
1159 | - session.execute(delete(metadata_table).where(metadata_table.c.key == 'Bookname language')) |
1160 | - except: |
1161 | - log.exception('Exception when upgrading Bookname language') |
1162 | - # Copy "download source" to "download_source" |
1163 | - try: |
1164 | - value_count = session.execute( |
1165 | - select( |
1166 | - [func.count(metadata_table.c.value)], |
1167 | - metadata_table.c.key == 'download source' |
1168 | - ) |
1169 | - ).scalar() |
1170 | - log.debug('download source: {count}'.format(count=value_count)) |
1171 | - if value_count > 0: |
1172 | - session.execute(insert(metadata_table).values( |
1173 | - key='download_source', |
1174 | - value=select( |
1175 | - [metadata_table.c.value], |
1176 | - metadata_table.c.key == 'download source' |
1177 | - ).as_scalar() |
1178 | - )) |
1179 | - session.execute(delete(metadata_table).where(metadata_table.c.key == 'download source')) |
1180 | - except: |
1181 | - log.exception('Exception when upgrading download source') |
1182 | - # Copy "download name" to "download_name" |
1183 | - try: |
1184 | - value_count = session.execute( |
1185 | - select( |
1186 | - [func.count(metadata_table.c.value)], |
1187 | - metadata_table.c.key == 'download name' |
1188 | - ) |
1189 | - ).scalar() |
1190 | - log.debug('download name: {count}'.format(count=value_count)) |
1191 | - if value_count > 0: |
1192 | - session.execute(insert(metadata_table).values( |
1193 | - key='download_name', |
1194 | - value=select( |
1195 | - [metadata_table.c.value], |
1196 | - metadata_table.c.key == 'download name' |
1197 | - ).as_scalar() |
1198 | - )) |
1199 | - session.execute(delete(metadata_table).where(metadata_table.c.key == 'download name')) |
1200 | - except: |
1201 | - log.exception('Exception when upgrading download name') |
1202 | - # Copy "proxy server" to "proxy_server" |
1203 | - try: |
1204 | - value_count = session.execute( |
1205 | - select( |
1206 | - [func.count(metadata_table.c.value)], |
1207 | - metadata_table.c.key == 'proxy server' |
1208 | - ) |
1209 | - ).scalar() |
1210 | - log.debug('proxy server: {count}'.format(count=value_count)) |
1211 | - if value_count > 0: |
1212 | - session.execute(insert(metadata_table).values( |
1213 | - key='proxy_server', |
1214 | - value=select( |
1215 | - [metadata_table.c.value], |
1216 | - metadata_table.c.key == 'proxy server' |
1217 | - ).as_scalar() |
1218 | - )) |
1219 | - session.execute(delete(metadata_table).where(metadata_table.c.key == 'proxy server')) |
1220 | - except: |
1221 | - log.exception('Exception when upgrading proxy server') |
1222 | - # Copy "proxy username" to "proxy_username" |
1223 | - try: |
1224 | - value_count = session.execute( |
1225 | - select( |
1226 | - [func.count(metadata_table.c.value)], |
1227 | - metadata_table.c.key == 'proxy username' |
1228 | - ) |
1229 | - ).scalar() |
1230 | - log.debug('proxy username: {count}'.format(count=value_count)) |
1231 | - if value_count > 0: |
1232 | - session.execute(insert(metadata_table).values( |
1233 | - key='proxy_username', |
1234 | - value=select( |
1235 | - [metadata_table.c.value], |
1236 | - metadata_table.c.key == 'proxy username' |
1237 | - ).as_scalar() |
1238 | - )) |
1239 | - session.execute(delete(metadata_table).where(metadata_table.c.key == 'proxy username')) |
1240 | - except: |
1241 | - log.exception('Exception when upgrading proxy username') |
1242 | - # Copy "proxy password" to "proxy_password" |
1243 | - try: |
1244 | - value_count = session.execute( |
1245 | - select( |
1246 | - [func.count(metadata_table.c.value)], |
1247 | - metadata_table.c.key == 'proxy password' |
1248 | - ) |
1249 | - ).scalar() |
1250 | - log.debug('proxy password: {count}'.format(count=value_count)) |
1251 | - if value_count > 0: |
1252 | - session.execute(insert(metadata_table).values( |
1253 | - key='proxy_password', |
1254 | - value=select( |
1255 | - [metadata_table.c.value], |
1256 | - metadata_table.c.key == 'proxy password' |
1257 | - ).as_scalar() |
1258 | - )) |
1259 | - session.execute(delete(metadata_table).where(metadata_table.c.key == 'proxy password')) |
1260 | - except: |
1261 | - log.exception('Exception when upgrading proxy password') |
1262 | - try: |
1263 | - session.execute(delete(metadata_table).where(metadata_table.c.key == 'dbversion')) |
1264 | - except: |
1265 | - log.exception('Exception when deleting dbversion') |
1266 | - session.commit() |
1267 | + log.info('No upgrades to perform') |
1268 | |
1269 | === modified file 'tests/functional/openlp_core_ui/test_exceptionform.py' |
1270 | --- tests/functional/openlp_core_ui/test_exceptionform.py 2016-06-25 14:41:06 +0000 |
1271 | +++ tests/functional/openlp_core_ui/test_exceptionform.py 2016-09-09 21:59:44 +0000 |
1272 | @@ -24,18 +24,13 @@ |
1273 | """ |
1274 | |
1275 | import os |
1276 | -import socket |
1277 | import tempfile |
1278 | -import urllib |
1279 | from unittest import TestCase |
1280 | from unittest.mock import mock_open |
1281 | |
1282 | -from PyQt5.QtCore import QUrlQuery |
1283 | - |
1284 | from openlp.core.common import Registry |
1285 | -from openlp.core.ui.firsttimeform import FirstTimeForm |
1286 | |
1287 | -from tests.functional import MagicMock, patch |
1288 | +from tests.functional import patch |
1289 | from tests.helpers.testmixin import TestMixin |
1290 | |
1291 | from openlp.core.ui import exceptionform |
1292 | |
1293 | === modified file 'tests/functional/openlp_plugins/bibles/test_bibleimport.py' |
1294 | --- tests/functional/openlp_plugins/bibles/test_bibleimport.py 2016-08-07 11:20:53 +0000 |
1295 | +++ tests/functional/openlp_plugins/bibles/test_bibleimport.py 2016-09-09 21:59:44 +0000 |
1296 | @@ -27,9 +27,12 @@ |
1297 | from lxml import etree, objectify |
1298 | |
1299 | from unittest import TestCase |
1300 | +from PyQt5.QtWidgets import QDialog |
1301 | |
1302 | from openlp.core.common.languages import Language |
1303 | +from openlp.core.lib.exceptions import ValidationError |
1304 | from openlp.plugins.bibles.lib.bibleimport import BibleImport |
1305 | +from openlp.plugins.bibles.lib.db import BibleDB |
1306 | from tests.functional import MagicMock, patch |
1307 | |
1308 | |
1309 | @@ -39,22 +42,103 @@ |
1310 | """ |
1311 | |
1312 | def setUp(self): |
1313 | - test_file = BytesIO(b'<?xml version="1.0" encoding="UTF-8" ?>\n' |
1314 | - b'<root>\n' |
1315 | - b' <data><div>Test<p>data</p><a>to</a>keep</div></data>\n' |
1316 | - b' <data><unsupported>Test<x>data</x><y>to</y>discard</unsupported></data>\n' |
1317 | - b'</root>') |
1318 | - self.file_patcher = patch('builtins.open', return_value=test_file) |
1319 | - self.log_patcher = patch('openlp.plugins.bibles.lib.bibleimport.log') |
1320 | + self.test_file = BytesIO( |
1321 | + b'<?xml version="1.0" encoding="UTF-8" ?>\n' |
1322 | + b'<root>\n' |
1323 | + b' <data><div>Test<p>data</p><a>to</a>keep</div></data>\n' |
1324 | + b' <data><unsupported>Test<x>data</x><y>to</y>discard</unsupported></data>\n' |
1325 | + b'</root>' |
1326 | + ) |
1327 | + self.open_patcher = patch('builtins.open') |
1328 | + self.addCleanup(self.open_patcher.stop) |
1329 | + self.mocked_open = self.open_patcher.start() |
1330 | + self.critical_error_message_box_patcher = \ |
1331 | + patch('openlp.plugins.bibles.lib.bibleimport.critical_error_message_box') |
1332 | + self.addCleanup(self.critical_error_message_box_patcher.stop) |
1333 | + self.mocked_critical_error_message_box = self.critical_error_message_box_patcher.start() |
1334 | self.setup_patcher = patch('openlp.plugins.bibles.lib.db.BibleDB._setup') |
1335 | - |
1336 | - self.addCleanup(self.file_patcher.stop) |
1337 | - self.addCleanup(self.log_patcher.stop) |
1338 | self.addCleanup(self.setup_patcher.stop) |
1339 | - |
1340 | - self.file_patcher.start() |
1341 | - self.mock_log = self.log_patcher.start() |
1342 | self.setup_patcher.start() |
1343 | + self.translate_patcher = patch('openlp.plugins.bibles.lib.bibleimport.translate', |
1344 | + side_effect=lambda module, string_to_translate, *args: string_to_translate) |
1345 | + self.addCleanup(self.translate_patcher.stop) |
1346 | + self.mocked_translate = self.translate_patcher.start() |
1347 | + self.registry_patcher = patch('openlp.plugins.bibles.lib.bibleimport.Registry') |
1348 | + self.addCleanup(self.registry_patcher.stop) |
1349 | + self.registry_patcher.start() |
1350 | + |
1351 | + def init_kwargs_none_test(self): |
1352 | + """ |
1353 | + Test the initialisation of the BibleImport Class when no key word arguments are supplied |
1354 | + """ |
1355 | + # GIVEN: A patched BibleDB._setup, BibleImport class and mocked parent |
1356 | + # WHEN: Creating an instance of BibleImport with no key word arguments |
1357 | + instance = BibleImport(MagicMock()) |
1358 | + |
1359 | + # THEN: The filename attribute should be None |
1360 | + self.assertIsNone(instance.filename) |
1361 | + self.assertIsInstance(instance, BibleDB) |
1362 | + |
1363 | + def init_kwargs_set_test(self): |
1364 | + """ |
1365 | + Test the initialisation of the BibleImport Class when supplied with select keyword arguments |
1366 | + """ |
1367 | + # GIVEN: A patched BibleDB._setup, BibleImport class and mocked parent |
1368 | + # WHEN: Creating an instance of BibleImport with selected key word arguments |
1369 | + kwargs = {'filename': 'bible.xml'} |
1370 | + instance = BibleImport(MagicMock(), **kwargs) |
1371 | + |
1372 | + # THEN: The filename keyword should be set to bible.xml |
1373 | + self.assertEqual(instance.filename, 'bible.xml') |
1374 | + self.assertIsInstance(instance, BibleDB) |
1375 | + |
1376 | + def get_language_canceled_test(self): |
1377 | + """ |
1378 | + Test the BibleImport.get_language method when the user rejects the dialog box |
1379 | + """ |
1380 | + # GIVEN: A mocked LanguageForm with an exec method which returns QtDialog.Rejected and an instance of BibleDB |
1381 | + with patch.object(BibleDB, '_setup'), patch('openlp.plugins.bibles.forms.LanguageForm') as mocked_language_form: |
1382 | + |
1383 | + # The integer value of QtDialog.Rejected is 0. Using the enumeration causes a seg fault for some reason |
1384 | + mocked_language_form_instance = MagicMock(**{'exec.return_value': 0}) |
1385 | + mocked_language_form.return_value = mocked_language_form_instance |
1386 | + instance = BibleImport(MagicMock()) |
1387 | + mocked_wizard = MagicMock() |
1388 | + instance.wizard = mocked_wizard |
1389 | + |
1390 | + # WHEN: Calling get_language() |
1391 | + result = instance.get_language() |
1392 | + |
1393 | + # THEN: get_language() should return False |
1394 | + mocked_language_form.assert_called_once_with(mocked_wizard) |
1395 | + mocked_language_form_instance.exec.assert_called_once_with(None) |
1396 | + self.assertFalse(result, 'get_language() should return False if the user rejects the dialog box') |
1397 | + |
1398 | + def get_language_accepted_test(self): |
1399 | + """ |
1400 | + Test the BibleImport.get_language method when the user accepts the dialog box |
1401 | + """ |
1402 | + # GIVEN: A mocked LanguageForm with an exec method which returns QtDialog.Accepted an instance of BibleDB and |
1403 | + # a combobox with the selected item data as 10 |
1404 | + with patch.object(BibleDB, 'save_meta'), patch.object(BibleDB, '_setup'), \ |
1405 | + patch('openlp.plugins.bibles.forms.LanguageForm') as mocked_language_form: |
1406 | + |
1407 | + # The integer value of QtDialog.Accepted is 1. Using the enumeration causes a seg fault for some reason |
1408 | + mocked_language_form_instance = MagicMock(**{'exec.return_value': 1, |
1409 | + 'language_combo_box.itemData.return_value': 10}) |
1410 | + mocked_language_form.return_value = mocked_language_form_instance |
1411 | + instance = BibleImport(MagicMock()) |
1412 | + mocked_wizard = MagicMock() |
1413 | + instance.wizard = mocked_wizard |
1414 | + |
1415 | + # WHEN: Calling get_language() |
1416 | + result = instance.get_language('Bible Name') |
1417 | + |
1418 | + # THEN: get_language() should return the id of the selected language in the combo box |
1419 | + mocked_language_form.assert_called_once_with(mocked_wizard) |
1420 | + mocked_language_form_instance.exec.assert_called_once_with('Bible Name') |
1421 | + self.assertEqual(result, 10, 'get_language() should return the id of the language the user has chosen when ' |
1422 | + 'they accept the dialog box') |
1423 | |
1424 | def get_language_id_language_found_test(self): |
1425 | """ |
1426 | @@ -63,7 +147,7 @@ |
1427 | # GIVEN: A mocked languages.get_language which returns language and an instance of BibleImport |
1428 | with patch('openlp.core.common.languages.get_language', return_value=Language(30, 'English', 'en')) \ |
1429 | as mocked_languages_get_language, \ |
1430 | - patch('openlp.plugins.bibles.lib.db.BibleDB.get_language') as mocked_db_get_language: |
1431 | + patch.object(BibleImport, 'get_language') as mocked_db_get_language: |
1432 | instance = BibleImport(MagicMock()) |
1433 | instance.save_meta = MagicMock() |
1434 | |
1435 | @@ -81,9 +165,8 @@ |
1436 | Test get_language_id() when called with a name not found in the languages list |
1437 | """ |
1438 | # GIVEN: A mocked languages.get_language which returns language and an instance of BibleImport |
1439 | - with patch('openlp.core.common.languages.get_language', return_value=None) \ |
1440 | - as mocked_languages_get_language, \ |
1441 | - patch('openlp.plugins.bibles.lib.db.BibleDB.get_language', return_value=20) as mocked_db_get_language: |
1442 | + with patch('openlp.core.common.languages.get_language', return_value=None) as mocked_languages_get_language, \ |
1443 | + patch.object(BibleImport, 'get_language', return_value=20) as mocked_db_get_language: |
1444 | instance = BibleImport(MagicMock()) |
1445 | instance.save_meta = MagicMock() |
1446 | |
1447 | @@ -103,8 +186,8 @@ |
1448 | # GIVEN: A mocked languages.get_language which returns None a mocked BibleDB.get_language which returns a |
1449 | # language id. |
1450 | with patch('openlp.core.common.languages.get_language', return_value=None) as mocked_languages_get_language, \ |
1451 | - patch('openlp.plugins.bibles.lib.db.BibleDB.get_language', return_value=40) as mocked_db_get_language: |
1452 | - self.mock_log.error.reset_mock() |
1453 | + patch.object(BibleImport, 'get_language', return_value=40) as mocked_db_get_language, \ |
1454 | + patch.object(BibleImport, 'log_error') as mocked_log_error: |
1455 | instance = BibleImport(MagicMock()) |
1456 | instance.save_meta = MagicMock() |
1457 | |
1458 | @@ -114,7 +197,7 @@ |
1459 | # THEN: The id of the language returned from BibleDB.get_language should be returned |
1460 | mocked_languages_get_language.assert_called_once_with('English') |
1461 | mocked_db_get_language.assert_called_once_with('KJV') |
1462 | - self.assertFalse(self.mock_log.error.called) |
1463 | + self.assertFalse(mocked_log_error.error.called) |
1464 | instance.save_meta.assert_called_once_with('language_id', 40) |
1465 | self.assertEqual(result, 40) |
1466 | |
1467 | @@ -125,8 +208,8 @@ |
1468 | # GIVEN: A mocked languages.get_language which returns None a mocked BibleDB.get_language which returns a |
1469 | # language id. |
1470 | with patch('openlp.core.common.languages.get_language', return_value=None) as mocked_languages_get_language, \ |
1471 | - patch('openlp.plugins.bibles.lib.db.BibleDB.get_language', return_value=None) as mocked_db_get_language: |
1472 | - self.mock_log.error.reset_mock() |
1473 | + patch.object(BibleImport, 'get_language', return_value=None) as mocked_db_get_language, \ |
1474 | + patch.object(BibleImport, 'log_error') as mocked_log_error: |
1475 | instance = BibleImport(MagicMock()) |
1476 | instance.save_meta = MagicMock() |
1477 | |
1478 | @@ -136,18 +219,148 @@ |
1479 | # THEN: None should be returned and an error should be logged |
1480 | mocked_languages_get_language.assert_called_once_with('Qwerty') |
1481 | mocked_db_get_language.assert_called_once_with('KJV') |
1482 | - self.mock_log.error.assert_called_once_with('Language detection failed when importing from "KJV". ' |
1483 | - 'User aborted language selection.') |
1484 | + mocked_log_error.assert_called_once_with( |
1485 | + 'Language detection failed when importing from "KJV". User aborted language selection.') |
1486 | self.assertFalse(instance.save_meta.called) |
1487 | self.assertIsNone(result) |
1488 | |
1489 | + def get_book_ref_id_by_name_get_book_test(self): |
1490 | + """ |
1491 | + Test get_book_ref_id_by_name when the book is found as a book in BiblesResourcesDB |
1492 | + """ |
1493 | + # GIVEN: An instance of BibleImport and a mocked BiblesResourcesDB which returns a book id when get_book is |
1494 | + # called |
1495 | + with patch.object(BibleImport, 'log_debug'), \ |
1496 | + patch('openlp.plugins.bibles.lib.bibleimport.BiblesResourcesDB', |
1497 | + **{'get_book.return_value': {'id': 20}}): |
1498 | + instance = BibleImport(MagicMock()) |
1499 | + |
1500 | + # WHEN: Calling get_book_ref_id_by_name |
1501 | + result = instance.get_book_ref_id_by_name('Gen', 66, 4) |
1502 | + |
1503 | + # THEN: The bible id should be returned |
1504 | + self.assertEqual(result, 20) |
1505 | + |
1506 | + def get_book_ref_id_by_name_get_alternative_book_name_test(self): |
1507 | + """ |
1508 | + Test get_book_ref_id_by_name when the book is found as an alternative book in BiblesResourcesDB |
1509 | + """ |
1510 | + # GIVEN: An instance of BibleImport and a mocked BiblesResourcesDB which returns a book id when |
1511 | + # get_alternative_book_name is called |
1512 | + with patch.object(BibleImport, 'log_debug'), \ |
1513 | + patch('openlp.plugins.bibles.lib.bibleimport.BiblesResourcesDB', |
1514 | + **{'get_book.return_value': None, 'get_alternative_book_name.return_value': 30}): |
1515 | + instance = BibleImport(MagicMock()) |
1516 | + |
1517 | + # WHEN: Calling get_book_ref_id_by_name |
1518 | + result = instance.get_book_ref_id_by_name('Gen', 66, 4) |
1519 | + |
1520 | + # THEN: The bible id should be returned |
1521 | + self.assertEqual(result, 30) |
1522 | + |
1523 | + def get_book_ref_id_by_name_get_book_reference_id_test(self): |
1524 | + """ |
1525 | + Test get_book_ref_id_by_name when the book is found as a book in AlternativeBookNamesDB |
1526 | + """ |
1527 | + # GIVEN: An instance of BibleImport and a mocked AlternativeBookNamesDB which returns a book id when |
1528 | + # get_book_reference_id is called |
1529 | + with patch.object(BibleImport, 'log_debug'), \ |
1530 | + patch('openlp.plugins.bibles.lib.bibleimport.BiblesResourcesDB', |
1531 | + **{'get_book.return_value': None, 'get_alternative_book_name.return_value': None}), \ |
1532 | + patch('openlp.plugins.bibles.lib.bibleimport.AlternativeBookNamesDB', |
1533 | + **{'get_book_reference_id.return_value': 40}): |
1534 | + instance = BibleImport(MagicMock()) |
1535 | + |
1536 | + # WHEN: Calling get_book_ref_id_by_name |
1537 | + result = instance.get_book_ref_id_by_name('Gen', 66, 4) |
1538 | + |
1539 | + # THEN: The bible id should be returned |
1540 | + self.assertEqual(result, 40) |
1541 | + |
1542 | + def get_book_ref_id_by_name_book_name_form_rejected_test(self): |
1543 | + """ |
1544 | + Test get_book_ref_id_by_name when the user rejects the BookNameForm |
1545 | + """ |
1546 | + # GIVEN: An instance of BibleImport and a mocked BookNameForm which simulates a user rejecting the dialog |
1547 | + with patch.object(BibleImport, 'log_debug'), patch.object(BibleImport, 'get_books'), \ |
1548 | + patch('openlp.plugins.bibles.lib.bibleimport.BiblesResourcesDB', |
1549 | + **{'get_book.return_value': None, 'get_alternative_book_name.return_value': None}), \ |
1550 | + patch('openlp.plugins.bibles.lib.bibleimport.AlternativeBookNamesDB', |
1551 | + **{'get_book_reference_id.return_value': None}), \ |
1552 | + patch('openlp.plugins.bibles.forms.BookNameForm', |
1553 | + return_value=MagicMock(**{'exec.return_value': QDialog.Rejected})): |
1554 | + instance = BibleImport(MagicMock()) |
1555 | + |
1556 | + # WHEN: Calling get_book_ref_id_by_name |
1557 | + result = instance.get_book_ref_id_by_name('Gen', 66, 4) |
1558 | + |
1559 | + # THEN: None should be returned |
1560 | + self.assertIsNone(result) |
1561 | + |
1562 | + def get_book_ref_id_by_name_book_name_form_accepted_test(self): |
1563 | + """ |
1564 | + Test get_book_ref_id_by_name when the user accepts the BookNameForm |
1565 | + """ |
1566 | + # GIVEN: An instance of BibleImport and a mocked BookNameForm which simulates a user accepting the dialog |
1567 | + with patch.object(BibleImport, 'log_debug'), patch.object(BibleImport, 'get_books'), \ |
1568 | + patch('openlp.plugins.bibles.lib.bibleimport.BiblesResourcesDB', |
1569 | + **{'get_book.return_value': None, 'get_alternative_book_name.return_value': None}), \ |
1570 | + patch('openlp.plugins.bibles.lib.bibleimport.AlternativeBookNamesDB', |
1571 | + **{'get_book_reference_id.return_value': None}) as mocked_alternative_book_names_db, \ |
1572 | + patch('openlp.plugins.bibles.forms.BookNameForm', |
1573 | + return_value=MagicMock(**{'exec.return_value': QDialog.Accepted, 'book_id': 50})): |
1574 | + instance = BibleImport(MagicMock()) |
1575 | + |
1576 | + # WHEN: Calling get_book_ref_id_by_name |
1577 | + result = instance.get_book_ref_id_by_name('Gen', 66, 4) |
1578 | + |
1579 | + # THEN: An alternative book name should be created and a bible id should be returned |
1580 | + mocked_alternative_book_names_db.create_alternative_book_name.assert_called_once_with('Gen', 50, 4) |
1581 | + self.assertEqual(result, 50) |
1582 | + |
1583 | + def is_compressed_compressed_test(self): |
1584 | + """ |
1585 | + Test is_compressed when the 'file' being tested is compressed |
1586 | + """ |
1587 | + # GIVEN: An instance of BibleImport and a mocked is_zipfile which returns True |
1588 | + with patch('openlp.plugins.bibles.lib.bibleimport.is_zipfile', return_value=True): |
1589 | + instance = BibleImport(MagicMock()) |
1590 | + |
1591 | + # WHEN: Calling is_compressed |
1592 | + result = instance.is_compressed('file.ext') |
1593 | + |
1594 | + # THEN: Then critical_error_message_box should be called informing the user that the file is compressed and |
1595 | + # True should be returned |
1596 | + self.mocked_critical_error_message_box.assert_called_once_with( |
1597 | + message='The file "file.ext" you supplied is compressed. You must decompress it before import.') |
1598 | + self.assertTrue(result) |
1599 | + |
1600 | + def is_compressed_not_compressed_test(self): |
1601 | + """ |
1602 | + Test is_compressed when the 'file' being tested is not compressed |
1603 | + """ |
1604 | + # GIVEN: An instance of BibleImport and a mocked is_zipfile which returns False |
1605 | + with patch('openlp.plugins.bibles.lib.bibleimport.is_zipfile', return_value=False): |
1606 | + instance = BibleImport(MagicMock()) |
1607 | + |
1608 | + # WHEN: Calling is_compressed |
1609 | + result = instance.is_compressed('file.ext') |
1610 | + |
1611 | + # THEN: False should be returned and critical_error_message_box should not have been called |
1612 | + self.assertFalse(result) |
1613 | + self.assertFalse(self.mocked_critical_error_message_box.called) |
1614 | + |
1615 | def parse_xml_etree_test(self): |
1616 | """ |
1617 | Test BibleImport.parse_xml() when called with the use_objectify default value |
1618 | """ |
1619 | - # GIVEN: A sample "file" to parse |
1620 | + # GIVEN: A sample "file" to parse and an instance of BibleImport |
1621 | + self.mocked_open.return_value = self.test_file |
1622 | + instance = BibleImport(MagicMock()) |
1623 | + instance.wizard = MagicMock() |
1624 | + |
1625 | # WHEN: Calling parse_xml |
1626 | - result = BibleImport.parse_xml('file.tst') |
1627 | + result = instance.parse_xml('file.tst') |
1628 | |
1629 | # THEN: The result returned should contain the correct data, and should be an instance of eetree_Element |
1630 | self.assertEqual(etree.tostring(result), |
1631 | @@ -159,9 +372,13 @@ |
1632 | """ |
1633 | Test BibleImport.parse_xml() when called with use_objectify set to True |
1634 | """ |
1635 | - # GIVEN: A sample "file" to parse |
1636 | + # GIVEN: A sample "file" to parse and an instance of BibleImport |
1637 | + self.mocked_open.return_value = self.test_file |
1638 | + instance = BibleImport(MagicMock()) |
1639 | + instance.wizard = MagicMock() |
1640 | + |
1641 | # WHEN: Calling parse_xml |
1642 | - result = BibleImport.parse_xml('file.tst', use_objectify=True) |
1643 | + result = instance.parse_xml('file.tst', use_objectify=True) |
1644 | |
1645 | # THEN: The result returned should contain the correct data, and should be an instance of ObjectifiedElement |
1646 | self.assertEqual(etree.tostring(result), |
1647 | @@ -173,11 +390,14 @@ |
1648 | """ |
1649 | Test BibleImport.parse_xml() when given a tuple of elements to remove |
1650 | """ |
1651 | - # GIVEN: A tuple of elements to remove |
1652 | + # GIVEN: A tuple of elements to remove and an instance of BibleImport |
1653 | + self.mocked_open.return_value = self.test_file |
1654 | elements = ('unsupported', 'x', 'y') |
1655 | + instance = BibleImport(MagicMock()) |
1656 | + instance.wizard = MagicMock() |
1657 | |
1658 | # WHEN: Calling parse_xml, with a test file |
1659 | - result = BibleImport.parse_xml('file.tst', elements=elements) |
1660 | + result = instance.parse_xml('file.tst', elements=elements) |
1661 | |
1662 | # THEN: The result returned should contain the correct data |
1663 | self.assertEqual(etree.tostring(result), |
1664 | @@ -187,11 +407,14 @@ |
1665 | """ |
1666 | Test BibleImport.parse_xml() when given a tuple of tags to remove |
1667 | """ |
1668 | - # GIVEN: A tuple of tags to remove |
1669 | + # GIVEN: A tuple of tags to remove and an instance of BibleImport |
1670 | + self.mocked_open.return_value = self.test_file |
1671 | tags = ('div', 'p', 'a') |
1672 | + instance = BibleImport(MagicMock()) |
1673 | + instance.wizard = MagicMock() |
1674 | |
1675 | # WHEN: Calling parse_xml, with a test file |
1676 | - result = BibleImport.parse_xml('file.tst', tags=tags) |
1677 | + result = instance.parse_xml('file.tst', tags=tags) |
1678 | |
1679 | # THEN: The result returned should contain the correct data |
1680 | self.assertEqual(etree.tostring(result), b'<root>\n <data>Testdatatokeep</data>\n <data><unsupported>Test' |
1681 | @@ -201,12 +424,192 @@ |
1682 | """ |
1683 | Test BibleImport.parse_xml() when given a tuple of elements and of tags to remove |
1684 | """ |
1685 | - # GIVEN: A tuple of elements and of tags to remove |
1686 | + # GIVEN: A tuple of elements and of tags to remove and an instacne of BibleImport |
1687 | + self.mocked_open.return_value = self.test_file |
1688 | elements = ('unsupported', 'x', 'y') |
1689 | tags = ('div', 'p', 'a') |
1690 | + instance = BibleImport(MagicMock()) |
1691 | + instance.wizard = MagicMock() |
1692 | |
1693 | # WHEN: Calling parse_xml, with a test file |
1694 | - result = BibleImport.parse_xml('file.tst', elements=elements, tags=tags) |
1695 | + result = instance.parse_xml('file.tst', elements=elements, tags=tags) |
1696 | |
1697 | # THEN: The result returned should contain the correct data |
1698 | self.assertEqual(etree.tostring(result), b'<root>\n <data>Testdatatokeep</data>\n <data/>\n</root>') |
1699 | + |
1700 | + def parse_xml_file_file_not_found_exception_test(self): |
1701 | + """ |
1702 | + Test that parse_xml handles a FileNotFoundError exception correctly |
1703 | + """ |
1704 | + with patch.object(BibleImport, 'log_exception') as mocked_log_exception: |
1705 | + # GIVEN: A mocked open which raises a FileNotFoundError and an instance of BibleImporter |
1706 | + exception = FileNotFoundError() |
1707 | + exception.filename = 'file.tst' |
1708 | + exception.strerror = 'No such file or directory' |
1709 | + self.mocked_open.side_effect = exception |
1710 | + importer = BibleImport(MagicMock(), path='.', name='.', filename='') |
1711 | + |
1712 | + # WHEN: Calling parse_xml |
1713 | + result = importer.parse_xml('file.tst') |
1714 | + |
1715 | + # THEN: parse_xml should have caught the error, informed the user and returned None |
1716 | + mocked_log_exception.assert_called_once_with('Opening file.tst failed.') |
1717 | + self.mocked_critical_error_message_box.assert_called_once_with( |
1718 | + title='An Error Occured When Opening A File', |
1719 | + message='The following error occurred when trying to open\nfile.tst:\n\nNo such file or directory') |
1720 | + self.assertIsNone(result) |
1721 | + |
1722 | + def parse_xml_file_permission_error_exception_test(self): |
1723 | + """ |
1724 | + Test that parse_xml handles a PermissionError exception correctly |
1725 | + """ |
1726 | + with patch.object(BibleImport, 'log_exception') as mocked_log_exception: |
1727 | + # GIVEN: A mocked open which raises a PermissionError and an instance of BibleImporter |
1728 | + exception = PermissionError() |
1729 | + exception.filename = 'file.tst' |
1730 | + exception.strerror = 'Permission denied' |
1731 | + self.mocked_open.side_effect = exception |
1732 | + importer = BibleImport(MagicMock(), path='.', name='.', filename='') |
1733 | + |
1734 | + # WHEN: Calling parse_xml |
1735 | + result = importer.parse_xml('file.tst') |
1736 | + |
1737 | + # THEN: parse_xml should have caught the error, informed the user and returned None |
1738 | + mocked_log_exception.assert_called_once_with('Opening file.tst failed.') |
1739 | + self.mocked_critical_error_message_box.assert_called_once_with( |
1740 | + title='An Error Occured When Opening A File', |
1741 | + message='The following error occurred when trying to open\nfile.tst:\n\nPermission denied') |
1742 | + self.assertIsNone(result) |
1743 | + |
1744 | + def set_current_chapter_test(self): |
1745 | + """ |
1746 | + Test set_current_chapter |
1747 | + """ |
1748 | + # GIVEN: An instance of BibleImport and a mocked wizard |
1749 | + importer = BibleImport(MagicMock(), path='.', name='.', filename='') |
1750 | + importer.wizard = MagicMock() |
1751 | + |
1752 | + # WHEN: Calling set_current_chapter |
1753 | + importer.set_current_chapter('Book_Name', 'Chapter') |
1754 | + |
1755 | + # THEN: Increment_progress_bar should have been called with a text string |
1756 | + importer.wizard.increment_progress_bar.assert_called_once_with('Importing Book_Name Chapter...') |
1757 | + |
1758 | + def validate_xml_file_compressed_file_test(self): |
1759 | + """ |
1760 | + Test that validate_xml_file raises a ValidationError when is_compressed returns True |
1761 | + """ |
1762 | + # GIVEN: A mocked parse_xml which returns None |
1763 | + with patch.object(BibleImport, 'is_compressed', return_value=True): |
1764 | + importer = BibleImport(MagicMock(), path='.', name='.', filename='') |
1765 | + |
1766 | + # WHEN: Calling is_compressed |
1767 | + # THEN: ValidationError should be raised, with the message 'Compressed file' |
1768 | + with self.assertRaises(ValidationError) as context: |
1769 | + importer.validate_xml_file('file.name', 'xbible') |
1770 | + self.assertEqual(context.exception.msg, 'Compressed file') |
1771 | + |
1772 | + def validate_xml_file_parse_xml_fails_test(self): |
1773 | + """ |
1774 | + Test that validate_xml_file raises a ValidationError when parse_xml returns None |
1775 | + """ |
1776 | + # GIVEN: A mocked parse_xml which returns None |
1777 | + with patch.object(BibleImport, 'parse_xml', return_value=None), \ |
1778 | + patch.object(BibleImport, 'is_compressed', return_value=False): |
1779 | + importer = BibleImport(MagicMock(), path='.', name='.', filename='') |
1780 | + |
1781 | + # WHEN: Calling validate_xml_file |
1782 | + # THEN: ValidationError should be raised, with the message 'Error when opening file' |
1783 | + # the user that an OpenSong bible was found |
1784 | + with self.assertRaises(ValidationError) as context: |
1785 | + importer.validate_xml_file('file.name', 'xbible') |
1786 | + self.assertEqual(context.exception.msg, 'Error when opening file') |
1787 | + |
1788 | + def validate_xml_file_success_test(self): |
1789 | + """ |
1790 | + Test that validate_xml_file returns True with valid XML |
1791 | + """ |
1792 | + # GIVEN: Some test data with an OpenSong Bible "bible" root tag |
1793 | + with patch.object(BibleImport, 'parse_xml', return_value=objectify.fromstring('<bible></bible>')), \ |
1794 | + patch.object(BibleImport, 'is_compressed', return_value=False): |
1795 | + importer = BibleImport(MagicMock(), path='.', name='.', filename='') |
1796 | + |
1797 | + # WHEN: Calling validate_xml_file |
1798 | + result = importer.validate_xml_file('file.name', 'bible') |
1799 | + |
1800 | + # THEN: True should be returned |
1801 | + self.assertTrue(result) |
1802 | + |
1803 | + def validate_xml_file_opensong_root_test(self): |
1804 | + """ |
1805 | + Test that validate_xml_file raises a ValidationError with an OpenSong root tag |
1806 | + """ |
1807 | + # GIVEN: Some test data with an Zefania root tag and an instance of BibleImport |
1808 | + with patch.object(BibleImport, 'parse_xml', return_value=objectify.fromstring('<bible></bible>')), \ |
1809 | + patch.object(BibleImport, 'is_compressed', return_value=False): |
1810 | + importer = BibleImport(MagicMock(), path='.', name='.', filename='') |
1811 | + |
1812 | + # WHEN: Calling validate_xml_file |
1813 | + # THEN: ValidationError should be raised, and the critical error message box should was called informing |
1814 | + # the user that an OpenSong bible was found |
1815 | + with self.assertRaises(ValidationError) as context: |
1816 | + importer.validate_xml_file('file.name', 'xbible') |
1817 | + self.assertEqual(context.exception.msg, 'Invalid xml.') |
1818 | + self.mocked_critical_error_message_box.assert_called_once_with( |
1819 | + message='Incorrect Bible file type supplied. This looks like an OpenSong XML bible.') |
1820 | + |
1821 | + def validate_xml_file_osis_root_test(self): |
1822 | + """ |
1823 | + Test that validate_xml_file raises a ValidationError with an OSIS root tag |
1824 | + """ |
1825 | + # GIVEN: Some test data with an Zefania root tag and an instance of BibleImport |
1826 | + with patch.object(BibleImport, 'parse_xml', return_value=objectify.fromstring( |
1827 | + '<osis xmlns=\'http://www.bibletechnologies.net/2003/OSIS/namespace\'></osis>')), \ |
1828 | + patch.object(BibleImport, 'is_compressed', return_value=False): |
1829 | + importer = BibleImport(MagicMock(), path='.', name='.', filename='') |
1830 | + |
1831 | + # WHEN: Calling validate_xml_file |
1832 | + # THEN: ValidationError should be raised, and the critical error message box should was called informing |
1833 | + # the user that an OSIS bible was found |
1834 | + with self.assertRaises(ValidationError) as context: |
1835 | + importer.validate_xml_file('file.name', 'xbible') |
1836 | + self.assertEqual(context.exception.msg, 'Invalid xml.') |
1837 | + self.mocked_critical_error_message_box.assert_called_once_with( |
1838 | + message='Incorrect Bible file type supplied. This looks like an OSIS XML bible.') |
1839 | + |
1840 | + def validate_xml_file_zefania_root_test(self): |
1841 | + """ |
1842 | + Test that validate_xml_file raises a ValidationError with an Zefania root tag |
1843 | + """ |
1844 | + # GIVEN: Some test data with an Zefania root tag and an instance of BibleImport |
1845 | + with patch.object(BibleImport, 'parse_xml', return_value=objectify.fromstring('<xmlbible></xmlbible>')), \ |
1846 | + patch.object(BibleImport, 'is_compressed', return_value=False): |
1847 | + importer = BibleImport(MagicMock(), path='.', name='.', filename='') |
1848 | + |
1849 | + # WHEN: Calling validate_xml_file |
1850 | + # THEN: ValidationError should be raised, and the critical error message box should was called informing |
1851 | + # the user that an Zefania bible was found |
1852 | + with self.assertRaises(ValidationError) as context: |
1853 | + importer.validate_xml_file('file.name', 'xbible') |
1854 | + self.assertEqual(context.exception.msg, 'Invalid xml.') |
1855 | + self.mocked_critical_error_message_box.assert_called_once_with( |
1856 | + message='Incorrect Bible file type supplied. This looks like an Zefania XML bible.') |
1857 | + |
1858 | + def validate_xml_file_unknown_root_test(self): |
1859 | + """ |
1860 | + Test that validate_xml_file raises a ValidationError with an unknown root tag |
1861 | + """ |
1862 | + # GIVEN: Some test data with an unknown root tag and an instance of BibleImport |
1863 | + with patch.object( |
1864 | + BibleImport, 'parse_xml', return_value=objectify.fromstring('<unknownbible></unknownbible>')), \ |
1865 | + patch.object(BibleImport, 'is_compressed', return_value=False): |
1866 | + importer = BibleImport(MagicMock(), path='.', name='.', filename='') |
1867 | + |
1868 | + # WHEN: Calling validate_xml_file |
1869 | + # THEN: ValidationError should be raised, and the critical error message box should was called informing |
1870 | + # the user that a unknown xml bible was found |
1871 | + with self.assertRaises(ValidationError) as context: |
1872 | + importer.validate_xml_file('file.name', 'xbible') |
1873 | + self.assertEqual(context.exception.msg, 'Invalid xml.') |
1874 | + self.mocked_critical_error_message_box.assert_called_once_with( |
1875 | + message='Incorrect Bible file type supplied. This looks like an unknown type of XML bible.') |
1876 | |
1877 | === renamed file 'tests/functional/openlp_plugins/bibles/test_http.py' => 'tests/functional/openlp_plugins/bibles/test_bibleserver.py' |
1878 | === modified file 'tests/functional/openlp_plugins/bibles/test_csvimport.py' |
1879 | --- tests/functional/openlp_plugins/bibles/test_csvimport.py 2016-08-09 20:56:04 +0000 |
1880 | +++ tests/functional/openlp_plugins/bibles/test_csvimport.py 2016-09-09 21:59:44 +0000 |
1881 | @@ -46,10 +46,10 @@ |
1882 | |
1883 | def setUp(self): |
1884 | self.manager_patcher = patch('openlp.plugins.bibles.lib.db.Manager') |
1885 | - self.registry_patcher = patch('openlp.plugins.bibles.lib.db.Registry') |
1886 | self.addCleanup(self.manager_patcher.stop) |
1887 | + self.manager_patcher.start() |
1888 | + self.registry_patcher = patch('openlp.plugins.bibles.lib.bibleimport.Registry') |
1889 | self.addCleanup(self.registry_patcher.stop) |
1890 | - self.manager_patcher.start() |
1891 | self.registry_patcher.start() |
1892 | |
1893 | def test_create_importer(self): |
1894 | @@ -194,9 +194,9 @@ |
1895 | # WHEN: Calling process_books |
1896 | result = importer.process_books(['Book 1']) |
1897 | |
1898 | - # THEN: increment_progress_bar should not be called and the return value should be None |
1899 | + # THEN: increment_progress_bar should not be called and the return value should be an empty dictionary |
1900 | self.assertFalse(importer.wizard.increment_progress_bar.called) |
1901 | - self.assertIsNone(result) |
1902 | + self.assertEqual(result, {}) |
1903 | |
1904 | def process_books_test(self): |
1905 | """ |
1906 | @@ -207,7 +207,6 @@ |
1907 | with patch('openlp.plugins.bibles.lib.db.BibleDB._setup'),\ |
1908 | patch('openlp.plugins.bibles.lib.importers.csvbible.translate'): |
1909 | importer = CSVBible(mocked_manager, path='.', name='.', booksfile='books.csv', versefile='verse.csv') |
1910 | - type(importer).application = PropertyMock() |
1911 | importer.find_and_create_book = MagicMock() |
1912 | importer.language_id = 10 |
1913 | importer.stop_import_flag = False |
1914 | @@ -222,7 +221,6 @@ |
1915 | # The returned data should be a dictionary with both song's id and names. |
1916 | self.assertEqual(importer.find_and_create_book.mock_calls, |
1917 | [call('1. Mosebog', 2, 10), call('2. Mosebog', 2, 10)]) |
1918 | - importer.application.process_events.assert_called_once_with() |
1919 | self.assertDictEqual(result, {1: '1. Mosebog', 2: '2. Mosebog'}) |
1920 | |
1921 | def process_verses_stopped_import_test(self): |
1922 | @@ -233,19 +231,16 @@ |
1923 | mocked_manager = MagicMock() |
1924 | with patch('openlp.plugins.bibles.lib.db.BibleDB._setup'): |
1925 | importer = CSVBible(mocked_manager, path='.', name='.', booksfile='books.csv', versefile='verse.csv') |
1926 | - type(importer).application = PropertyMock() |
1927 | importer.get_book_name = MagicMock() |
1928 | importer.session = MagicMock() |
1929 | importer.stop_import_flag = True |
1930 | importer.wizard = MagicMock() |
1931 | |
1932 | # WHEN: Calling process_verses |
1933 | - result = importer.process_verses([], []) |
1934 | + result = importer.process_verses(['Dummy Verse'], []) |
1935 | |
1936 | # THEN: get_book_name should not be called and the return value should be None |
1937 | self.assertFalse(importer.get_book_name.called) |
1938 | - importer.wizard.increment_progress_bar.assert_called_once_with('Importing verses... done.') |
1939 | - importer.application.process_events.assert_called_once_with() |
1940 | self.assertIsNone(result) |
1941 | |
1942 | def process_verses_successful_test(self): |
1943 | @@ -257,7 +252,6 @@ |
1944 | with patch('openlp.plugins.bibles.lib.db.BibleDB._setup'),\ |
1945 | patch('openlp.plugins.bibles.lib.importers.csvbible.translate'): |
1946 | importer = CSVBible(mocked_manager, path='.', name='.', booksfile='books.csv', versefile='verse.csv') |
1947 | - type(importer).application = PropertyMock() |
1948 | importer.create_verse = MagicMock() |
1949 | importer.get_book = MagicMock(return_value=Book('1', '1', '1. Mosebog', '1Mos')) |
1950 | importer.get_book_name = MagicMock(return_value='1. Mosebog') |
1951 | @@ -280,7 +274,6 @@ |
1952 | [call('1', 1, 1, 'I Begyndelsen skabte Gud Himmelen og Jorden.'), |
1953 | call('1', 1, 2, 'Og Jorden var øde og tom, og der var Mørke over Verdensdybet. ' |
1954 | 'Men Guds Ånd svævede over Vandene.')]) |
1955 | - importer.application.process_events.assert_called_once_with() |
1956 | |
1957 | def do_import_invalid_language_id_test(self): |
1958 | """ |
1959 | @@ -288,73 +281,16 @@ |
1960 | """ |
1961 | # GIVEN: An instance of CSVBible and a mocked get_language which simulates the user cancelling the language box |
1962 | mocked_manager = MagicMock() |
1963 | - with patch('openlp.plugins.bibles.lib.db.BibleDB._setup'),\ |
1964 | - patch('openlp.plugins.bibles.lib.importers.csvbible.log') as mocked_log: |
1965 | + with patch('openlp.plugins.bibles.lib.db.BibleDB._setup'): |
1966 | importer = CSVBible(mocked_manager, path='.', name='.', booksfile='books.csv', versefile='verse.csv') |
1967 | importer.get_language = MagicMock(return_value=None) |
1968 | |
1969 | # WHEN: Calling do_import |
1970 | result = importer.do_import('Bible Name') |
1971 | |
1972 | - # THEN: The log.exception method should have been called to show that it reached the except clause. |
1973 | - # False should be returned. |
1974 | + # THEN: The False should be returned. |
1975 | importer.get_language.assert_called_once_with('Bible Name') |
1976 | - mocked_log.exception.assert_called_once_with('Could not import CSV bible') |
1977 | - self.assertFalse(result) |
1978 | - |
1979 | - def do_import_stop_import_test(self): |
1980 | - """ |
1981 | - Test do_import when the import is stopped |
1982 | - """ |
1983 | - # GIVEN: An instance of CSVBible with stop_import set to True |
1984 | - mocked_manager = MagicMock() |
1985 | - with patch('openlp.plugins.bibles.lib.db.BibleDB._setup'),\ |
1986 | - patch('openlp.plugins.bibles.lib.importers.csvbible.log') as mocked_log: |
1987 | - importer = CSVBible(mocked_manager, path='.', name='.', booksfile='books.csv', versefile='verse.csv') |
1988 | - importer.get_language = MagicMock(return_value=10) |
1989 | - importer.parse_csv_file = MagicMock(return_value=['Book 1', 'Book 2', 'Book 3']) |
1990 | - importer.process_books = MagicMock() |
1991 | - importer.stop_import_flag = True |
1992 | - importer.wizard = MagicMock() |
1993 | - |
1994 | - # WHEN: Calling do_import |
1995 | - result = importer.do_import('Bible Name') |
1996 | - |
1997 | - # THEN: log.exception should not be called, parse_csv_file should only be called once, |
1998 | - # and False should be returned. |
1999 | - self.assertFalse(mocked_log.exception.called) |
2000 | - importer.parse_csv_file.assert_called_once_with('books.csv', Book) |
2001 | - importer.process_books.assert_called_once_with(['Book 1', 'Book 2', 'Book 3']) |
2002 | - self.assertFalse(result) |
2003 | - |
2004 | - def do_import_stop_import_2_test(self): |
2005 | - """ |
2006 | - Test do_import when the import is stopped |
2007 | - """ |
2008 | - # GIVEN: An instance of CSVBible with stop_import which is True the second time of calling |
2009 | - mocked_manager = MagicMock() |
2010 | - with patch('openlp.plugins.bibles.lib.db.BibleDB._setup'),\ |
2011 | - patch('openlp.plugins.bibles.lib.importers.csvbible.log') as mocked_log: |
2012 | - CSVBible.stop_import_flag = PropertyMock(side_effect=[False, True]) |
2013 | - importer = CSVBible(mocked_manager, path='.', name='.', booksfile='books.csv', versefile='verses.csv') |
2014 | - importer.get_language = MagicMock(return_value=10) |
2015 | - importer.parse_csv_file = MagicMock(side_effect=[['Book 1'], ['Verse 1']]) |
2016 | - importer.process_books = MagicMock(return_value=['Book 1']) |
2017 | - importer.process_verses = MagicMock(return_value=['Verse 1']) |
2018 | - importer.wizard = MagicMock() |
2019 | - |
2020 | - # WHEN: Calling do_import |
2021 | - result = importer.do_import('Bible Name') |
2022 | - |
2023 | - # THEN: log.exception should not be called, parse_csv_file should be called twice, |
2024 | - # and False should be returned. |
2025 | - self.assertFalse(mocked_log.exception.called) |
2026 | - self.assertEqual(importer.parse_csv_file.mock_calls, [call('books.csv', Book), call('verses.csv', Verse)]) |
2027 | - importer.process_verses.assert_called_once_with(['Verse 1'], ['Book 1']) |
2028 | - self.assertFalse(result) |
2029 | - |
2030 | - # Cleanup |
2031 | - del CSVBible.stop_import_flag |
2032 | + self.assertFalse(result) |
2033 | |
2034 | def do_import_success_test(self): |
2035 | """ |
2036 | @@ -362,8 +298,7 @@ |
2037 | """ |
2038 | # GIVEN: An instance of CSVBible |
2039 | mocked_manager = MagicMock() |
2040 | - with patch('openlp.plugins.bibles.lib.db.BibleDB._setup'),\ |
2041 | - patch('openlp.plugins.bibles.lib.importers.csvbible.log') as mocked_log: |
2042 | + with patch('openlp.plugins.bibles.lib.db.BibleDB._setup'): |
2043 | importer = CSVBible(mocked_manager, path='.', name='.', booksfile='books.csv', versefile='verses.csv') |
2044 | importer.get_language = MagicMock(return_value=10) |
2045 | importer.parse_csv_file = MagicMock(side_effect=[['Book 1'], ['Verse 1']]) |
2046 | @@ -376,9 +311,8 @@ |
2047 | # WHEN: Calling do_import |
2048 | result = importer.do_import('Bible Name') |
2049 | |
2050 | - # THEN: log.exception should not be called, parse_csv_file should be called twice, |
2051 | + # THEN: parse_csv_file should be called twice, |
2052 | # and True should be returned. |
2053 | - self.assertFalse(mocked_log.exception.called) |
2054 | self.assertEqual(importer.parse_csv_file.mock_calls, [call('books.csv', Book), call('verses.csv', Verse)]) |
2055 | importer.process_books.assert_called_once_with(['Book 1']) |
2056 | importer.process_verses.assert_called_once_with(['Verse 1'], ['Book 1']) |
2057 | @@ -413,6 +347,6 @@ |
2058 | # THEN: The create_verse() method should have been called with each verse in the file. |
2059 | self.assertTrue(importer.create_verse.called) |
2060 | for verse_tag, verse_text in test_data['verses']: |
2061 | - importer.create_verse.assert_any_call(importer.get_book().id, '1', verse_tag, verse_text) |
2062 | + importer.create_verse.assert_any_call(importer.get_book().id, 1, verse_tag, verse_text) |
2063 | importer.create_book.assert_any_call('1. Mosebog', importer.get_book_ref_id_by_name(), 1) |
2064 | importer.create_book.assert_any_call('1. Krønikebog', importer.get_book_ref_id_by_name(), 1) |
2065 | |
2066 | === modified file 'tests/functional/openlp_plugins/bibles/test_db.py' |
2067 | --- tests/functional/openlp_plugins/bibles/test_db.py 2016-08-03 20:10:41 +0000 |
2068 | +++ tests/functional/openlp_plugins/bibles/test_db.py 2016-09-09 21:59:44 +0000 |
2069 | @@ -25,63 +25,9 @@ |
2070 | |
2071 | from unittest import TestCase |
2072 | |
2073 | -from openlp.plugins.bibles.lib.db import BibleDB |
2074 | -from tests.functional import MagicMock, patch |
2075 | - |
2076 | |
2077 | class TestBibleDB(TestCase): |
2078 | """ |
2079 | Test the functions in the BibleDB class. |
2080 | """ |
2081 | - |
2082 | - def test_get_language_canceled(self): |
2083 | - """ |
2084 | - Test the BibleDB.get_language method when the user rejects the dialog box |
2085 | - """ |
2086 | - # GIVEN: A mocked LanguageForm with an exec method which returns QtDialog.Rejected and an instance of BibleDB |
2087 | - with patch('openlp.plugins.bibles.lib.db.BibleDB._setup'),\ |
2088 | - patch('openlp.plugins.bibles.forms.LanguageForm') as mocked_language_form: |
2089 | - |
2090 | - # The integer value of QtDialog.Rejected is 0. Using the enumeration causes a seg fault for some reason |
2091 | - mocked_language_form_instance = MagicMock(**{'exec.return_value': 0}) |
2092 | - mocked_language_form.return_value = mocked_language_form_instance |
2093 | - mocked_parent = MagicMock() |
2094 | - instance = BibleDB(mocked_parent) |
2095 | - mocked_wizard = MagicMock() |
2096 | - instance.wizard = mocked_wizard |
2097 | - |
2098 | - # WHEN: Calling get_language() |
2099 | - result = instance.get_language() |
2100 | - |
2101 | - # THEN: get_language() should return False |
2102 | - mocked_language_form.assert_called_once_with(mocked_wizard) |
2103 | - mocked_language_form_instance.exec.assert_called_once_with(None) |
2104 | - self.assertFalse(result, 'get_language() should return False if the user rejects the dialog box') |
2105 | - |
2106 | - def test_get_language_accepted(self): |
2107 | - """ |
2108 | - Test the BibleDB.get_language method when the user accepts the dialog box |
2109 | - """ |
2110 | - # GIVEN: A mocked LanguageForm with an exec method which returns QtDialog.Accepted an instance of BibleDB and |
2111 | - # a combobox with the selected item data as 10 |
2112 | - with patch('openlp.plugins.bibles.lib.db.BibleDB._setup'), \ |
2113 | - patch('openlp.plugins.bibles.lib.db.BibleDB.save_meta'), \ |
2114 | - patch('openlp.plugins.bibles.forms.LanguageForm') as mocked_language_form: |
2115 | - |
2116 | - # The integer value of QtDialog.Accepted is 1. Using the enumeration causes a seg fault for some reason |
2117 | - mocked_language_form_instance = MagicMock(**{'exec.return_value': 1, |
2118 | - 'language_combo_box.itemData.return_value': 10}) |
2119 | - mocked_language_form.return_value = mocked_language_form_instance |
2120 | - mocked_parent = MagicMock() |
2121 | - instance = BibleDB(mocked_parent) |
2122 | - mocked_wizard = MagicMock() |
2123 | - instance.wizard = mocked_wizard |
2124 | - |
2125 | - # WHEN: Calling get_language() |
2126 | - result = instance.get_language('Bible Name') |
2127 | - |
2128 | - # THEN: get_language() should return the id of the selected language in the combo box |
2129 | - mocked_language_form.assert_called_once_with(mocked_wizard) |
2130 | - mocked_language_form_instance.exec.assert_called_once_with('Bible Name') |
2131 | - self.assertEqual(result, 10, 'get_language() should return the id of the language the user has chosen when ' |
2132 | - 'they accept the dialog box') |
2133 | + pass |
2134 | |
2135 | === modified file 'tests/functional/openlp_plugins/bibles/test_opensongimport.py' |
2136 | --- tests/functional/openlp_plugins/bibles/test_opensongimport.py 2016-08-09 20:45:25 +0000 |
2137 | +++ tests/functional/openlp_plugins/bibles/test_opensongimport.py 2016-09-09 21:59:44 +0000 |
2138 | @@ -23,32 +23,38 @@ |
2139 | This module contains tests for the OpenSong Bible importer. |
2140 | """ |
2141 | |
2142 | +import json |
2143 | import os |
2144 | -import json |
2145 | from unittest import TestCase |
2146 | |
2147 | -from tests.functional import MagicMock, patch |
2148 | -from openlp.plugins.bibles.lib.importers.opensong import OpenSongBible |
2149 | -from openlp.plugins.bibles.lib.db import BibleDB |
2150 | +from lxml import objectify |
2151 | + |
2152 | +from tests.functional import MagicMock, patch, call |
2153 | +from tests.helpers.testmixin import TestMixin |
2154 | +from openlp.core.common import Registry |
2155 | +from openlp.plugins.bibles.lib.importers.opensong import OpenSongBible, get_text, parse_chapter_number |
2156 | +from openlp.plugins.bibles.lib.bibleimport import BibleImport |
2157 | |
2158 | TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), |
2159 | '..', '..', '..', 'resources', 'bibles')) |
2160 | |
2161 | |
2162 | -class TestOpenSongImport(TestCase): |
2163 | +class TestOpenSongImport(TestCase, TestMixin): |
2164 | """ |
2165 | Test the functions in the :mod:`opensongimport` module. |
2166 | """ |
2167 | |
2168 | def setUp(self): |
2169 | - self.registry_patcher = patch('openlp.plugins.bibles.lib.db.Registry') |
2170 | - self.registry_patcher.start() |
2171 | + self.find_and_create_book_patch = patch.object(BibleImport, 'find_and_create_book') |
2172 | + self.addCleanup(self.find_and_create_book_patch.stop) |
2173 | + self.mocked_find_and_create_book = self.find_and_create_book_patch.start() |
2174 | self.manager_patcher = patch('openlp.plugins.bibles.lib.db.Manager') |
2175 | + self.addCleanup(self.manager_patcher.stop) |
2176 | self.manager_patcher.start() |
2177 | - |
2178 | - def tearDown(self): |
2179 | - self.registry_patcher.stop() |
2180 | - self.manager_patcher.stop() |
2181 | + self.setup_application() |
2182 | + self.app.process_events = MagicMock() |
2183 | + Registry.create() |
2184 | + Registry().register('application', self.app) |
2185 | |
2186 | def test_create_importer(self): |
2187 | """ |
2188 | @@ -61,7 +67,332 @@ |
2189 | importer = OpenSongBible(mocked_manager, path='.', name='.', filename='') |
2190 | |
2191 | # THEN: The importer should be an instance of BibleDB |
2192 | - self.assertIsInstance(importer, BibleDB) |
2193 | + self.assertIsInstance(importer, BibleImport) |
2194 | + |
2195 | + def get_text_no_text_test(self): |
2196 | + """ |
2197 | + Test that get_text handles elements containing text in a combination of text and tail attributes |
2198 | + """ |
2199 | + # GIVEN: Some test data which contains an empty element and an instance of OpenSongBible |
2200 | + test_data = objectify.fromstring('<element></element>') |
2201 | + |
2202 | + # WHEN: Calling get_text |
2203 | + result = get_text(test_data) |
2204 | + |
2205 | + # THEN: A blank string should be returned |
2206 | + self.assertEqual(result, '') |
2207 | + |
2208 | + def get_text_text_test(self): |
2209 | + """ |
2210 | + Test that get_text handles elements containing text in a combination of text and tail attributes |
2211 | + """ |
2212 | + # GIVEN: Some test data which contains all possible permutation of text and tail text possible and an instance |
2213 | + # of OpenSongBible |
2214 | + test_data = objectify.fromstring('<element>Element text ' |
2215 | + '<sub_text_tail>sub_text_tail text </sub_text_tail>sub_text_tail tail ' |
2216 | + '<sub_text>sub_text text </sub_text>' |
2217 | + '<sub_tail></sub_tail>sub_tail tail</element>') |
2218 | + |
2219 | + # WHEN: Calling get_text |
2220 | + result = get_text(test_data) |
2221 | + |
2222 | + # THEN: The text returned should be as expected |
2223 | + self.assertEqual(result, 'Element text sub_text_tail text sub_text_tail tail sub_text text sub_tail tail') |
2224 | + |
2225 | + def parse_chapter_number_test(self): |
2226 | + """ |
2227 | + Test parse_chapter_number when supplied with chapter number and an instance of OpenSongBible |
2228 | + """ |
2229 | + # GIVEN: The number 10 represented as a string |
2230 | + # WHEN: Calling parse_chapter_nnumber |
2231 | + result = parse_chapter_number('10', 0) |
2232 | + |
2233 | + # THEN: The 10 should be returned as an Int |
2234 | + self.assertEqual(result, 10) |
2235 | + |
2236 | + def parse_chapter_number_empty_attribute_test(self): |
2237 | + """ |
2238 | + Testparse_chapter_number when the chapter number is an empty string. (Bug #1074727) |
2239 | + """ |
2240 | + # GIVEN: An empty string, and the previous chapter number set as 12 and an instance of OpenSongBible |
2241 | + # WHEN: Calling parse_chapter_number |
2242 | + result = parse_chapter_number('', 12) |
2243 | + |
2244 | + # THEN: parse_chapter_number should increment the previous verse number |
2245 | + self.assertEqual(result, 13) |
2246 | + |
2247 | + def parse_verse_number_valid_verse_no_test(self): |
2248 | + """ |
2249 | + Test parse_verse_number when supplied with a valid verse number |
2250 | + """ |
2251 | + # GIVEN: An instance of OpenSongBible, the number 15 represented as a string and an instance of OpenSongBible |
2252 | + importer = OpenSongBible(MagicMock(), path='.', name='.', filename='') |
2253 | + |
2254 | + # WHEN: Calling parse_verse_number |
2255 | + result = importer.parse_verse_number('15', 0) |
2256 | + |
2257 | + # THEN: parse_verse_number should return the verse number |
2258 | + self.assertEqual(result, 15) |
2259 | + |
2260 | + def parse_verse_number_verse_range_test(self): |
2261 | + """ |
2262 | + Test parse_verse_number when supplied with a verse range |
2263 | + """ |
2264 | + # GIVEN: An instance of OpenSongBible, and the range 24-26 represented as a string |
2265 | + importer = OpenSongBible(MagicMock(), path='.', name='.', filename='') |
2266 | + |
2267 | + # WHEN: Calling parse_verse_number |
2268 | + result = importer.parse_verse_number('24-26', 0) |
2269 | + |
2270 | + # THEN: parse_verse_number should return the first verse number in the range |
2271 | + self.assertEqual(result, 24) |
2272 | + |
2273 | + def parse_verse_number_invalid_verse_no_test(self): |
2274 | + """ |
2275 | + Test parse_verse_number when supplied with a invalid verse number |
2276 | + """ |
2277 | + # GIVEN: An instance of OpenSongBible, a non numeric string represented as a string |
2278 | + importer = OpenSongBible(MagicMock(), path='.', name='.', filename='') |
2279 | + |
2280 | + # WHEN: Calling parse_verse_number |
2281 | + result = importer.parse_verse_number('invalid', 41) |
2282 | + |
2283 | + # THEN: parse_verse_number should increment the previous verse number |
2284 | + self.assertEqual(result, 42) |
2285 | + |
2286 | + def parse_verse_number_empty_attribute_test(self): |
2287 | + """ |
2288 | + Test parse_verse_number when the verse number is an empty string. (Bug #1074727) |
2289 | + """ |
2290 | + # GIVEN: An instance of OpenSongBible, an empty string, and the previous verse number set as 14 |
2291 | + importer = OpenSongBible(MagicMock(), path='.', name='.', filename='') |
2292 | + # WHEN: Calling parse_verse_number |
2293 | + result = importer.parse_verse_number('', 14) |
2294 | + |
2295 | + # THEN: parse_verse_number should increment the previous verse number |
2296 | + self.assertEqual(result, 15) |
2297 | + |
2298 | + def parse_verse_number_invalid_type_test(self): |
2299 | + """ |
2300 | + Test parse_verse_number when the verse number is an invalid type) |
2301 | + """ |
2302 | + with patch.object(OpenSongBible, 'log_warning')as mocked_log_warning: |
2303 | + # GIVEN: An instanceofOpenSongBible, a Tuple, and the previous verse number set as 12 |
2304 | + importer = OpenSongBible(MagicMock(), path='.', name='.', filename='') |
2305 | + |
2306 | + # WHEN: Calling parse_verse_number |
2307 | + result = importer.parse_verse_number((1, 2, 3), 12) |
2308 | + |
2309 | + # THEN: parse_verse_number should log the verse number it was called with increment the previous verse |
2310 | + # number |
2311 | + mocked_log_warning.assert_called_once_with('Illegal verse number: (1, 2, 3)') |
2312 | + self.assertEqual(result, 13) |
2313 | + |
2314 | + def process_books_stop_import_test(self): |
2315 | + """ |
2316 | + Test process_books when stop_import is set to True |
2317 | + """ |
2318 | + # GIVEN: An instance of OpenSongBible |
2319 | + importer = OpenSongBible(MagicMock(), path='.', name='.', filename='') |
2320 | + |
2321 | + # WHEN: stop_import_flag is set to True |
2322 | + importer.stop_import_flag = True |
2323 | + importer.process_books(['Book']) |
2324 | + |
2325 | + # THEN: find_and_create_book should not have been called |
2326 | + self.assertFalse(self.mocked_find_and_create_book.called) |
2327 | + |
2328 | + def process_books_completes_test(self): |
2329 | + """ |
2330 | + Test process_books when it processes all books |
2331 | + """ |
2332 | + # GIVEN: An instance of OpenSongBible Importer and two mocked books |
2333 | + self.mocked_find_and_create_book.side_effect = ['db_book1', 'db_book2'] |
2334 | + with patch.object(OpenSongBible, 'process_chapters') as mocked_process_chapters: |
2335 | + importer = OpenSongBible(MagicMock(), path='.', name='.', filename='') |
2336 | + |
2337 | + book1 = MagicMock() |
2338 | + book1.attrib = {'n': 'Name1'} |
2339 | + book1.c = 'Chapter1' |
2340 | + book2 = MagicMock() |
2341 | + book2.attrib = {'n': 'Name2'} |
2342 | + book2.c = 'Chapter2' |
2343 | + importer.language_id = 10 |
2344 | + importer.session = MagicMock() |
2345 | + importer.stop_import_flag = False |
2346 | + |
2347 | + # WHEN: Calling process_books with the two books |
2348 | + importer.process_books([book1, book2]) |
2349 | + |
2350 | + # THEN: find_and_create_book and process_books should be called with the details from the mocked books |
2351 | + self.assertEqual(self.mocked_find_and_create_book.call_args_list, |
2352 | + [call('Name1', 2, 10), call('Name2', 2, 10)]) |
2353 | + self.assertEqual(mocked_process_chapters.call_args_list, |
2354 | + [call('db_book1', 'Chapter1'), call('db_book2', 'Chapter2')]) |
2355 | + self.assertEqual(importer.session.commit.call_count, 2) |
2356 | + |
2357 | + def process_chapters_stop_import_test(self): |
2358 | + """ |
2359 | + Test process_chapters when stop_import is set to True |
2360 | + """ |
2361 | + # GIVEN: An isntance of OpenSongBible |
2362 | + importer = OpenSongBible(MagicMock(), path='.', name='.', filename='') |
2363 | + importer.parse_chapter_number = MagicMock() |
2364 | + |
2365 | + # WHEN: stop_import_flag is set to True |
2366 | + importer.stop_import_flag = True |
2367 | + importer.process_chapters('Book', ['Chapter1']) |
2368 | + |
2369 | + # THEN: importer.parse_chapter_number not have been called |
2370 | + self.assertFalse(importer.parse_chapter_number.called) |
2371 | + |
2372 | + @patch('openlp.plugins.bibles.lib.importers.opensong.parse_chapter_number', **{'side_effect': [1, 2]}) |
2373 | + def process_chapters_completes_test(self, mocked_parse_chapter_number): |
2374 | + """ |
2375 | + Test process_chapters when it completes |
2376 | + """ |
2377 | + # GIVEN: An instance of OpenSongBible |
2378 | + importer = OpenSongBible(MagicMock(), path='.', name='.', filename='') |
2379 | + importer.wizard = MagicMock() |
2380 | + |
2381 | + # WHEN: called with some valid data |
2382 | + book = MagicMock() |
2383 | + book.name = "Book" |
2384 | + chapter1 = MagicMock() |
2385 | + chapter1.attrib = {'n': '1'} |
2386 | + chapter1.c = 'Chapter1' |
2387 | + chapter1.v = ['Chapter1 Verses'] |
2388 | + chapter2 = MagicMock() |
2389 | + chapter2.attrib = {'n': '2'} |
2390 | + chapter2.c = 'Chapter2' |
2391 | + chapter2.v = ['Chapter2 Verses'] |
2392 | + |
2393 | + importer.process_verses = MagicMock() |
2394 | + importer.stop_import_flag = False |
2395 | + importer.process_chapters(book, [chapter1, chapter2]) |
2396 | + |
2397 | + # THEN: parse_chapter_number, process_verses and increment_process_bar should have been called |
2398 | + self.assertEqual(mocked_parse_chapter_number.call_args_list, [call('1', 0), call('2', 1)]) |
2399 | + self.assertEqual( |
2400 | + importer.process_verses.call_args_list, |
2401 | + [call(book, 1, ['Chapter1 Verses']), call(book, 2, ['Chapter2 Verses'])]) |
2402 | + self.assertEqual(importer.wizard.increment_progress_bar.call_args_list, |
2403 | + [call('Importing Book 1...'), call('Importing Book 2...')]) |
2404 | + |
2405 | + def process_verses_stop_import_test(self): |
2406 | + """ |
2407 | + Test process_verses when stop_import is set to True |
2408 | + """ |
2409 | + # GIVEN: An isntance of OpenSongBible |
2410 | + importer = OpenSongBible(MagicMock(), path='.', name='.', filename='') |
2411 | + importer.parse_verse_number = MagicMock() |
2412 | + |
2413 | + # WHEN: stop_import_flag is set to True |
2414 | + importer.stop_import_flag = True |
2415 | + importer.process_verses('Book', 1, 'Verses') |
2416 | + |
2417 | + # THEN: importer.parse_verse_number not have been called |
2418 | + self.assertFalse(importer.parse_verse_number.called) |
2419 | + |
2420 | + def process_verses_completes_test(self): |
2421 | + """ |
2422 | + Test process_verses when it completes |
2423 | + """ |
2424 | + with patch('openlp.plugins.bibles.lib.importers.opensong.get_text', |
2425 | + **{'side_effect': ['Verse1 Text', 'Verse2 Text']}) as mocked_get_text, \ |
2426 | + patch.object(OpenSongBible, 'parse_verse_number', |
2427 | + **{'side_effect': [1, 2]}) as mocked_parse_verse_number: |
2428 | + # GIVEN: An instance of OpenSongBible |
2429 | + importer = OpenSongBible(MagicMock(), path='.', name='.', filename='') |
2430 | + importer.wizard = MagicMock() |
2431 | + |
2432 | + # WHEN: called with some valid data |
2433 | + book = MagicMock() |
2434 | + book.id = 1 |
2435 | + verse1 = MagicMock() |
2436 | + verse1.attrib = {'n': '1'} |
2437 | + verse1.c = 'Chapter1' |
2438 | + verse1.v = ['Chapter1 Verses'] |
2439 | + verse2 = MagicMock() |
2440 | + verse2.attrib = {'n': '2'} |
2441 | + verse2.c = 'Chapter2' |
2442 | + verse2.v = ['Chapter2 Verses'] |
2443 | + |
2444 | + importer.create_verse = MagicMock() |
2445 | + importer.stop_import_flag = False |
2446 | + importer.process_verses(book, 1, [verse1, verse2]) |
2447 | + |
2448 | + # THEN: parse_chapter_number, process_verses and increment_process_bar should have been called |
2449 | + self.assertEqual(mocked_parse_verse_number.call_args_list, [call('1', 0), call('2', 1)]) |
2450 | + self.assertEqual(mocked_get_text.call_args_list, [call(verse1), call(verse2)]) |
2451 | + self.assertEqual( |
2452 | + importer.create_verse.call_args_list, |
2453 | + [call(1, 1, 1, 'Verse1 Text'), call(1, 1, 2, 'Verse2 Text')]) |
2454 | + |
2455 | + def do_import_parse_xml_fails_test(self): |
2456 | + """ |
2457 | + Test do_import when parse_xml fails (returns None) |
2458 | + """ |
2459 | + # GIVEN: An instance of OpenSongBible and a mocked parse_xml which returns False |
2460 | + with patch.object(OpenSongBible, 'log_debug'), \ |
2461 | + patch.object(OpenSongBible, 'validate_xml_file'), \ |
2462 | + patch.object(OpenSongBible, 'parse_xml', return_value=None), \ |
2463 | + patch.object(OpenSongBible, 'get_language_id') as mocked_language_id: |
2464 | + importer = OpenSongBible(MagicMock(), path='.', name='.', filename='') |
2465 | + |
2466 | + # WHEN: Calling do_import |
2467 | + result = importer.do_import() |
2468 | + |
2469 | + # THEN: do_import should return False and get_language_id should have not been called |
2470 | + self.assertFalse(result) |
2471 | + self.assertFalse(mocked_language_id.called) |
2472 | + |
2473 | + def do_import_no_language_test(self): |
2474 | + """ |
2475 | + Test do_import when the user cancels the language selection dialog |
2476 | + """ |
2477 | + # GIVEN: An instance of OpenSongBible and a mocked get_language which returns False |
2478 | + with patch.object(OpenSongBible, 'log_debug'), \ |
2479 | + patch.object(OpenSongBible, 'validate_xml_file'), \ |
2480 | + patch.object(OpenSongBible, 'parse_xml'), \ |
2481 | + patch.object(OpenSongBible, 'get_language_id', return_value=False), \ |
2482 | + patch.object(OpenSongBible, 'process_books') as mocked_process_books: |
2483 | + importer = OpenSongBible(MagicMock(), path='.', name='.', filename='') |
2484 | + |
2485 | + # WHEN: Calling do_import |
2486 | + result = importer.do_import() |
2487 | + |
2488 | + # THEN: do_import should return False and process_books should have not been called |
2489 | + self.assertFalse(result) |
2490 | + self.assertFalse(mocked_process_books.called) |
2491 | + |
2492 | + def do_import_completes_test(self): |
2493 | + """ |
2494 | + Test do_import when it completes successfully |
2495 | + """ |
2496 | + # GIVEN: An instance of OpenSongBible |
2497 | + with patch.object(OpenSongBible, 'log_debug'), \ |
2498 | + patch.object(OpenSongBible, 'validate_xml_file'), \ |
2499 | + patch.object(OpenSongBible, 'parse_xml'), \ |
2500 | + patch.object(OpenSongBible, 'get_language_id', return_value=10), \ |
2501 | + patch.object(OpenSongBible, 'process_books'): |
2502 | + importer = OpenSongBible(MagicMock(), path='.', name='.', filename='') |
2503 | + |
2504 | + # WHEN: Calling do_import |
2505 | + result = importer.do_import() |
2506 | + |
2507 | + # THEN: do_import should return True |
2508 | + self.assertTrue(result) |
2509 | + |
2510 | + |
2511 | +class TestOpenSongImportFileImports(TestCase, TestMixin): |
2512 | + """ |
2513 | + Test the functions in the :mod:`opensongimport` module. |
2514 | + """ |
2515 | + def setUp(self): |
2516 | + self.manager_patcher = patch('openlp.plugins.bibles.lib.db.Manager') |
2517 | + self.addCleanup(self.manager_patcher.stop) |
2518 | + self.manager_patcher.start() |
2519 | |
2520 | def test_file_import(self): |
2521 | """ |
2522 | @@ -92,22 +423,3 @@ |
2523 | self.assertTrue(importer.create_verse.called) |
2524 | for verse_tag, verse_text in test_data['verses']: |
2525 | importer.create_verse.assert_any_call(importer.create_book().id, 1, int(verse_tag), verse_text) |
2526 | - |
2527 | - def test_zefania_import_error(self): |
2528 | - """ |
2529 | - Test that we give an error message if trying to import a zefania bible |
2530 | - """ |
2531 | - # GIVEN: A mocked out "manager" and mocked out critical_error_message_box and an import |
2532 | - with patch('openlp.plugins.bibles.lib.importers.opensong.critical_error_message_box') as \ |
2533 | - mocked_critical_error_message_box: |
2534 | - mocked_manager = MagicMock() |
2535 | - importer = OpenSongBible(mocked_manager, path='.', name='.', filename='') |
2536 | - |
2537 | - # WHEN: An trying to import a zefania bible |
2538 | - importer.filename = os.path.join(TEST_PATH, 'zefania-dk1933.xml') |
2539 | - importer.do_import() |
2540 | - |
2541 | - # THEN: The importer should have "shown" an error message |
2542 | - mocked_critical_error_message_box.assert_called_with(message='Incorrect Bible file type supplied. ' |
2543 | - 'This looks like a Zefania XML bible, ' |
2544 | - 'please use the Zefania import option.') |
2545 | |
2546 | === modified file 'tests/functional/openlp_plugins/bibles/test_osisimport.py' |
2547 | --- tests/functional/openlp_plugins/bibles/test_osisimport.py 2016-08-09 20:45:25 +0000 |
2548 | +++ tests/functional/openlp_plugins/bibles/test_osisimport.py 2016-09-09 21:59:44 +0000 |
2549 | @@ -27,29 +27,35 @@ |
2550 | import json |
2551 | from unittest import TestCase |
2552 | |
2553 | -from tests.functional import MagicMock, patch |
2554 | +from tests.functional import MagicMock, call, patch |
2555 | +from openlp.plugins.bibles.lib.bibleimport import BibleImport |
2556 | +from openlp.plugins.bibles.lib.db import BibleDB |
2557 | from openlp.plugins.bibles.lib.importers.osis import OSISBible |
2558 | -from openlp.plugins.bibles.lib.db import BibleDB |
2559 | |
2560 | -TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), |
2561 | - '..', '..', '..', 'resources', 'bibles')) |
2562 | +TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..', 'resources', 'bibles')) |
2563 | |
2564 | |
2565 | class TestOsisImport(TestCase): |
2566 | """ |
2567 | Test the functions in the :mod:`osisimport` module. |
2568 | """ |
2569 | - |
2570 | def setUp(self): |
2571 | - self.registry_patcher = patch('openlp.plugins.bibles.lib.db.Registry') |
2572 | + self.etree_patcher = patch('openlp.plugins.bibles.lib.importers.osis.etree') |
2573 | + self.addCleanup(self.etree_patcher.stop) |
2574 | + self.mocked_etree = self.etree_patcher.start() |
2575 | + self.create_verse_patcher = patch('openlp.plugins.bibles.lib.db.BibleDB.create_verse') |
2576 | + self.addCleanup(self.create_verse_patcher.stop) |
2577 | + self.mocked_create_verse = self.create_verse_patcher.start() |
2578 | + self.find_and_create_book_patch = patch.object(BibleImport, 'find_and_create_book') |
2579 | + self.addCleanup(self.find_and_create_book_patch.stop) |
2580 | + self.mocked_find_and_create_book = self.find_and_create_book_patch.start() |
2581 | + self.registry_patcher = patch('openlp.plugins.bibles.lib.bibleimport.Registry') |
2582 | + self.addCleanup(self.registry_patcher.stop) |
2583 | self.registry_patcher.start() |
2584 | self.manager_patcher = patch('openlp.plugins.bibles.lib.db.Manager') |
2585 | + self.addCleanup(self.manager_patcher.stop) |
2586 | self.manager_patcher.start() |
2587 | |
2588 | - def tearDown(self): |
2589 | - self.registry_patcher.stop() |
2590 | - self.manager_patcher.stop() |
2591 | - |
2592 | def test_create_importer(self): |
2593 | """ |
2594 | Test creating an instance of the OSIS file importer |
2595 | @@ -63,6 +69,353 @@ |
2596 | # THEN: The importer should be an instance of BibleDB |
2597 | self.assertIsInstance(importer, BibleDB) |
2598 | |
2599 | + def process_books_stop_import_test(self): |
2600 | + """ |
2601 | + Test process_books when stop_import is set to True |
2602 | + """ |
2603 | + # GIVEN: An instance of OSISBible adn some mocked data |
2604 | + importer = OSISBible(MagicMock(), path='.', name='.', filename='') |
2605 | + mocked_data = MagicMock(**{'xpath.return_value': ['Book']}) |
2606 | + |
2607 | + # WHEN: stop_import_flag is set to True and process_books is called |
2608 | + importer.stop_import_flag = True |
2609 | + importer.process_books(mocked_data) |
2610 | + |
2611 | + # THEN: find_and_create_book should not have been called |
2612 | + self.assertFalse(self.mocked_find_and_create_book.called) |
2613 | + |
2614 | + def process_books_completes_test(self): |
2615 | + """ |
2616 | + Test process_books when it processes all books |
2617 | + """ |
2618 | + # GIVEN: An instance of OSISBible Importer and two mocked books |
2619 | + self.mocked_find_and_create_book.side_effect = ['db_book1', 'db_book2'] |
2620 | + with patch.object(OSISBible, 'process_chapters') as mocked_process_chapters: |
2621 | + importer = OSISBible(MagicMock(), path='.', name='.', filename='') |
2622 | + |
2623 | + book1 = MagicMock() |
2624 | + book1.get.return_value = 'Name1' |
2625 | + book2 = MagicMock() |
2626 | + book2.get.return_value = 'Name2' |
2627 | + mocked_data = MagicMock(**{'xpath.return_value': [book1, book2]}) |
2628 | + importer.language_id = 10 |
2629 | + importer.session = MagicMock() |
2630 | + importer.stop_import_flag = False |
2631 | + |
2632 | + # WHEN: Calling process_books with the two books |
2633 | + importer.process_books(mocked_data) |
2634 | + |
2635 | + # THEN: find_and_create_book and process_books should be called with the details from the mocked books |
2636 | + self.assertEqual(self.mocked_find_and_create_book.call_args_list, |
2637 | + [call('Name1', 2, 10), call('Name2', 2, 10)]) |
2638 | + self.assertEqual(mocked_process_chapters.call_args_list, |
2639 | + [call('db_book1', book1), call('db_book2', book2)]) |
2640 | + self.assertEqual(importer.session.commit.call_count, 2) |
2641 | + |
2642 | + def process_chapters_verse_in_chapter_verse_text_test(self): |
2643 | + """ |
2644 | + Test process_chapters when supplied with an etree element with a verse element nested in it |
2645 | + """ |
2646 | + with patch('openlp.plugins.bibles.lib.importers.osis.verse_in_chapter', return_value=True), \ |
2647 | + patch('openlp.plugins.bibles.lib.importers.osis.text_in_verse', return_value=True), \ |
2648 | + patch.object(OSISBible, 'set_current_chapter') as mocked_set_current_chapter, \ |
2649 | + patch.object(OSISBible, 'process_verse') as mocked_process_verse: |
2650 | + |
2651 | + # GIVEN: Some test data and an instance of OSISBible |
2652 | + test_book = MagicMock() |
2653 | + test_verse = MagicMock() |
2654 | + test_verse.tail = '\n ' # Whitespace |
2655 | + test_verse.text = 'Verse Text' |
2656 | + test_chapter = MagicMock() |
2657 | + test_chapter.__iter__.return_value = [test_verse] |
2658 | + test_chapter.get.side_effect = lambda x: {'osisID': '1.2.4', 'sID': '999'}.get(x) |
2659 | + importer = OSISBible(MagicMock(), path='.', name='.', filename='') |
2660 | + |
2661 | + # WHEN: Calling process_chapters |
2662 | + importer.process_chapters(test_book, [test_chapter]) |
2663 | + |
2664 | + # THEN: set_current_chapter and process_verse should have been called with the test data |
2665 | + mocked_set_current_chapter.assert_called_once_with(test_book.name, 2) |
2666 | + mocked_process_verse.assert_called_once_with(test_book, 2, test_verse) |
2667 | + |
2668 | + def process_chapters_verse_in_chapter_verse_milestone_test(self): |
2669 | + """ |
2670 | + Test process_chapters when supplied with an etree element with a verse element nested, when the verse system is |
2671 | + based on milestones |
2672 | + """ |
2673 | + with patch('openlp.plugins.bibles.lib.importers.osis.verse_in_chapter', return_value=True), \ |
2674 | + patch('openlp.plugins.bibles.lib.importers.osis.text_in_verse', return_value=False), \ |
2675 | + patch.object(OSISBible, 'set_current_chapter') as mocked_set_current_chapter, \ |
2676 | + patch.object(OSISBible, 'process_verse') as mocked_process_verse: |
2677 | + |
2678 | + # GIVEN: Some test data and an instance of OSISBible |
2679 | + test_book = MagicMock() |
2680 | + test_verse = MagicMock() |
2681 | + test_verse.tail = '\n ' # Whitespace |
2682 | + test_verse.text = 'Verse Text' |
2683 | + test_chapter = MagicMock() |
2684 | + test_chapter.__iter__.return_value = [test_verse] |
2685 | + test_chapter.get.side_effect = lambda x: {'osisID': '1.2.4', 'sID': '999'}.get(x) |
2686 | + importer = OSISBible(MagicMock(), path='.', name='.', filename='') |
2687 | + |
2688 | + # WHEN: Calling process_chapters |
2689 | + importer.process_chapters(test_book, [test_chapter]) |
2690 | + |
2691 | + # THEN: set_current_chapter and process_verse should have been called with the test data |
2692 | + mocked_set_current_chapter.assert_called_once_with(test_book.name, 2) |
2693 | + mocked_process_verse.assert_called_once_with(test_book, 2, test_verse, use_milestones=True) |
2694 | + |
2695 | + def process_chapters_milestones_chapter_no_sid_test(self): |
2696 | + """ |
2697 | + Test process_chapters when supplied with an etree element with a chapter and verse element in the milestone |
2698 | + configuration, where the chapter is the "closing" milestone. (Missing the sID attribute) |
2699 | + """ |
2700 | + with patch('openlp.plugins.bibles.lib.importers.osis.verse_in_chapter', return_value=False), \ |
2701 | + patch.object(OSISBible, 'set_current_chapter') as mocked_set_current_chapter, \ |
2702 | + patch.object(OSISBible, 'process_verse') as mocked_process_verse: |
2703 | + |
2704 | + # GIVEN: Some test data and an instance of OSISBible |
2705 | + test_book = MagicMock() |
2706 | + test_chapter = MagicMock() |
2707 | + test_chapter.tag = '{http://www.bibletechnologies.net/2003/OSIS/namespace}chapter' |
2708 | + test_chapter.get.side_effect = lambda x: {'osisID': '1.2.4'}.get(x) |
2709 | + |
2710 | + # WHEN: Calling process_chapters |
2711 | + importer = OSISBible(MagicMock(), path='.', name='.', filename='') |
2712 | + importer.process_chapters(test_book, [test_chapter]) |
2713 | + |
2714 | + # THEN: neither set_current_chapter or process_verse should have been called |
2715 | + self.assertFalse(mocked_set_current_chapter.called) |
2716 | + self.assertFalse(mocked_process_verse.called) |
2717 | + |
2718 | + def process_chapters_milestones_chapter_sid_test(self): |
2719 | + """ |
2720 | + Test process_chapters when supplied with an etree element with a chapter and verse element in the milestone |
2721 | + configuration, where the chapter is the "opening" milestone. (Has the sID attribute) |
2722 | + """ |
2723 | + with patch('openlp.plugins.bibles.lib.importers.osis.verse_in_chapter', return_value=False), \ |
2724 | + patch.object(OSISBible, 'set_current_chapter') as mocked_set_current_chapter, \ |
2725 | + patch.object(OSISBible, 'process_verse') as mocked_process_verse: |
2726 | + |
2727 | + # GIVEN: Some test data and an instance of OSISBible |
2728 | + test_book = MagicMock() |
2729 | + test_chapter = MagicMock() |
2730 | + test_chapter.tag = '{http://www.bibletechnologies.net/2003/OSIS/namespace}chapter' |
2731 | + test_chapter.get.side_effect = lambda x: {'osisID': '1.2.4', 'sID': '999'}.get(x) |
2732 | + importer = OSISBible(MagicMock(), path='.', name='.', filename='') |
2733 | + |
2734 | + # WHEN: Calling process_chapters |
2735 | + importer.process_chapters(test_book, [test_chapter]) |
2736 | + |
2737 | + # THEN: set_current_chapter should have been called with the test data |
2738 | + mocked_set_current_chapter.assert_called_once_with(test_book.name, 2) |
2739 | + self.assertFalse(mocked_process_verse.called) |
2740 | + |
2741 | + def process_chapters_milestones_verse_tag_test(self): |
2742 | + """ |
2743 | + Test process_chapters when supplied with an etree element with a chapter and verse element in the milestone |
2744 | + configuration, where the verse is the "opening" milestone. (Has the sID attribute) |
2745 | + """ |
2746 | + with patch('openlp.plugins.bibles.lib.importers.osis.verse_in_chapter', return_value=False), \ |
2747 | + patch.object(OSISBible, 'set_current_chapter') as mocked_set_current_chapter, \ |
2748 | + patch.object(OSISBible, 'process_verse') as mocked_process_verse: |
2749 | + |
2750 | + # GIVEN: Some test data and an instance of OSISBible |
2751 | + test_book = MagicMock() |
2752 | + test_verse = MagicMock() |
2753 | + test_verse.get.side_effect = lambda x: {'osisID': '1.2.4', 'sID': '999'}.get(x) |
2754 | + test_verse.tag = '{http://www.bibletechnologies.net/2003/OSIS/namespace}verse' |
2755 | + test_verse.tail = '\n ' # Whitespace |
2756 | + test_verse.text = 'Verse Text' |
2757 | + |
2758 | + # WHEN: Calling process_chapters |
2759 | + importer = OSISBible(MagicMock(), path='.', name='.', filename='') |
2760 | + importer.process_chapters(test_book, [test_verse]) |
2761 | + |
2762 | + # THEN: process_verse should have been called with the test data |
2763 | + self.assertFalse(mocked_set_current_chapter.called) |
2764 | + mocked_process_verse.assert_called_once_with(test_book, 0, test_verse, use_milestones=True) |
2765 | + |
2766 | + def process_verse_no_osis_id_test(self): |
2767 | + """ |
2768 | + Test process_verse when the element supplied does not have and osisID attribute |
2769 | + """ |
2770 | + # GIVEN: An instance of OSISBible, and some mocked test data |
2771 | + test_book = MagicMock() |
2772 | + test_verse = MagicMock() |
2773 | + test_verse.get.side_effect = lambda x: {}.get(x) |
2774 | + test_verse.tail = 'Verse Text' |
2775 | + test_verse.text = None |
2776 | + importer = OSISBible(MagicMock(), path='.', name='.', filename='') |
2777 | + |
2778 | + # WHEN: Calling process_verse with the test data |
2779 | + importer.process_verse(test_book, 2, test_verse) |
2780 | + |
2781 | + # THEN: create_verse should not have been called |
2782 | + self.assertFalse(self.mocked_create_verse.called) |
2783 | + |
2784 | + def process_verse_use_milestones_no_s_id_test(self): |
2785 | + """ |
2786 | + Test process_verse when called with use_milestones set to True, but the element supplied does not have and sID |
2787 | + attribute |
2788 | + """ |
2789 | + # GIVEN: An instance of OSISBible, and some mocked test data |
2790 | + test_book = MagicMock() |
2791 | + test_verse = MagicMock() |
2792 | + test_verse.get.side_effect = lambda x: {}.get(x) |
2793 | + test_verse.tail = 'Verse Text' |
2794 | + test_verse.text = None |
2795 | + importer = OSISBible(MagicMock(), path='.', name='.', filename='') |
2796 | + |
2797 | + # WHEN: Calling process_verse with the test data |
2798 | + importer.process_verse(test_book, 2, test_verse) |
2799 | + |
2800 | + # THEN: create_verse should not have been called |
2801 | + self.assertFalse(self.mocked_create_verse.called) |
2802 | + |
2803 | + def process_verse_use_milestones_no_tail_test(self): |
2804 | + """ |
2805 | + Test process_verse when called with use_milestones set to True, but the element supplied does not have a 'tail' |
2806 | + """ |
2807 | + # GIVEN: An instance of OSISBible, and some mocked test data |
2808 | + test_book = MagicMock() |
2809 | + test_verse = MagicMock() |
2810 | + test_verse.tail = None |
2811 | + test_verse.text = None |
2812 | + test_verse.get.side_effect = lambda x: {'osisID': '1.2.4', 'sID': '999'}.get(x) |
2813 | + importer = OSISBible(MagicMock(), path='.', name='.', filename='') |
2814 | + |
2815 | + # WHEN: Calling process_verse with the test data |
2816 | + importer.process_verse(test_book, 2, test_verse, use_milestones=True) |
2817 | + |
2818 | + # THEN: create_verse should not have been called |
2819 | + self.assertFalse(self.mocked_create_verse.called) |
2820 | + |
2821 | + def process_verse_use_milestones_success_test(self): |
2822 | + """ |
2823 | + Test process_verse when called with use_milestones set to True, and the verse element successfully imports |
2824 | + """ |
2825 | + # GIVEN: An instance of OSISBible, and some mocked test data |
2826 | + test_book = MagicMock() |
2827 | + test_book.id = 1 |
2828 | + test_verse = MagicMock() |
2829 | + test_verse.tail = 'Verse Text' |
2830 | + test_verse.text = None |
2831 | + test_verse.get.side_effect = lambda x: {'osisID': '1.2.4', 'sID': '999'}.get(x) |
2832 | + importer = OSISBible(MagicMock(), path='.', name='.', filename='') |
2833 | + |
2834 | + # WHEN: Calling process_verse with the test data |
2835 | + importer.process_verse(test_book, 2, test_verse, use_milestones=True) |
2836 | + |
2837 | + # THEN: create_verse should have been called with the test data |
2838 | + self.mocked_create_verse.assert_called_once_with(1, 2, 4, 'Verse Text') |
2839 | + |
2840 | + def process_verse_no_text_test(self): |
2841 | + """ |
2842 | + Test process_verse when called with an empty verse element |
2843 | + """ |
2844 | + # GIVEN: An instance of OSISBible, and some mocked test data |
2845 | + test_book = MagicMock() |
2846 | + test_book.id = 1 |
2847 | + test_verse = MagicMock() |
2848 | + test_verse.tail = '\n ' # Whitespace |
2849 | + test_verse.text = None |
2850 | + test_verse.get.side_effect = lambda x: {'osisID': '1.2.4', 'sID': '999'}.get(x) |
2851 | + importer = OSISBible(MagicMock(), path='.', name='.', filename='') |
2852 | + |
2853 | + # WHEN: Calling process_verse with the test data |
2854 | + importer.process_verse(test_book, 2, test_verse) |
2855 | + |
2856 | + # THEN: create_verse should not have been called |
2857 | + self.assertFalse(self.mocked_create_verse.called) |
2858 | + |
2859 | + def process_verse_success_test(self): |
2860 | + """ |
2861 | + Test process_verse when called with an element with text set |
2862 | + """ |
2863 | + # GIVEN: An instance of OSISBible, and some mocked test data |
2864 | + test_book = MagicMock() |
2865 | + test_book.id = 1 |
2866 | + test_verse = MagicMock() |
2867 | + test_verse.tail = '\n ' # Whitespace |
2868 | + test_verse.text = 'Verse Text' |
2869 | + test_verse.get.side_effect = lambda x: {'osisID': '1.2.4', 'sID': '999'}.get(x) |
2870 | + importer = OSISBible(MagicMock(), path='.', name='.', filename='') |
2871 | + |
2872 | + # WHEN: Calling process_verse with the test data |
2873 | + importer.process_verse(test_book, 2, test_verse) |
2874 | + |
2875 | + # THEN: create_verse should have been called with the test data |
2876 | + self.mocked_create_verse.assert_called_once_with(1, 2, 4, 'Verse Text') |
2877 | + |
2878 | + def do_import_parse_xml_fails_test(self): |
2879 | + """ |
2880 | + Test do_import when parse_xml fails (returns None) |
2881 | + """ |
2882 | + # GIVEN: An instance of OpenSongBible and a mocked parse_xml which returns False |
2883 | + with patch.object(OSISBible, 'log_debug'), \ |
2884 | + patch.object(OSISBible, 'validate_xml_file'), \ |
2885 | + patch.object(OSISBible, 'parse_xml', return_value=None), \ |
2886 | + patch.object(OSISBible, 'get_language_id') as mocked_language_id: |
2887 | + importer = OSISBible(MagicMock(), path='.', name='.', filename='') |
2888 | + |
2889 | + # WHEN: Calling do_import |
2890 | + result = importer.do_import() |
2891 | + |
2892 | + # THEN: do_import should return False and get_language_id should have not been called |
2893 | + self.assertFalse(result) |
2894 | + self.assertFalse(mocked_language_id.called) |
2895 | + |
2896 | + def do_import_no_language_test(self): |
2897 | + """ |
2898 | + Test do_import when the user cancels the language selection dialog |
2899 | + """ |
2900 | + # GIVEN: An instance of OpenSongBible and a mocked get_language which returns False |
2901 | + with patch.object(OSISBible, 'log_debug'), \ |
2902 | + patch.object(OSISBible, 'validate_xml_file'), \ |
2903 | + patch.object(OSISBible, 'parse_xml'), \ |
2904 | + patch.object(OSISBible, 'get_language_id', **{'return_value': False}), \ |
2905 | + patch.object(OSISBible, 'process_books') as mocked_process_books: |
2906 | + importer = OSISBible(MagicMock(), path='.', name='.', filename='') |
2907 | + |
2908 | + # WHEN: Calling do_import |
2909 | + result = importer.do_import() |
2910 | + |
2911 | + # THEN: do_import should return False and process_books should have not been called |
2912 | + self.assertFalse(result) |
2913 | + self.assertFalse(mocked_process_books.called) |
2914 | + |
2915 | + def do_import_completes_test(self): |
2916 | + """ |
2917 | + Test do_import when it completes successfully |
2918 | + """ |
2919 | + # GIVEN: An instance of OpenSongBible |
2920 | + with patch.object(OSISBible, 'log_debug'), \ |
2921 | + patch.object(OSISBible, 'validate_xml_file'), \ |
2922 | + patch.object(OSISBible, 'parse_xml'), \ |
2923 | + patch.object(OSISBible, 'get_language_id', **{'return_value': 10}), \ |
2924 | + patch.object(OSISBible, 'process_books'): |
2925 | + importer = OSISBible(MagicMock(), path='.', name='.', filename='') |
2926 | + |
2927 | + # WHEN: Calling do_import |
2928 | + result = importer.do_import() |
2929 | + |
2930 | + # THEN: do_import should return True |
2931 | + self.assertTrue(result) |
2932 | + |
2933 | + |
2934 | +class TestOsisImportFileImports(TestCase): |
2935 | + """ |
2936 | + Test the functions in the :mod:`osisimport` module. |
2937 | + """ |
2938 | + def setUp(self): |
2939 | + self.registry_patcher = patch('openlp.plugins.bibles.lib.bibleimport.Registry') |
2940 | + self.addCleanup(self.registry_patcher.stop) |
2941 | + self.registry_patcher.start() |
2942 | + self.manager_patcher = patch('openlp.plugins.bibles.lib.db.Manager') |
2943 | + self.addCleanup(self.manager_patcher.stop) |
2944 | + self.manager_patcher.start() |
2945 | + |
2946 | def test_file_import_nested_tags(self): |
2947 | """ |
2948 | Test the actual import of OSIS Bible file, with nested chapter and verse tags |
2949 | @@ -91,7 +444,7 @@ |
2950 | # THEN: The create_verse() method should have been called with each verse in the file. |
2951 | self.assertTrue(importer.create_verse.called) |
2952 | for verse_tag, verse_text in test_data['verses']: |
2953 | - importer.create_verse.assert_any_call(importer.create_book().id, '1', verse_tag, verse_text) |
2954 | + importer.create_verse.assert_any_call(importer.create_book().id, 1, verse_tag, verse_text) |
2955 | |
2956 | def test_file_import_mixed_tags(self): |
2957 | """ |
2958 | @@ -121,7 +474,7 @@ |
2959 | # THEN: The create_verse() method should have been called with each verse in the file. |
2960 | self.assertTrue(importer.create_verse.called) |
2961 | for verse_tag, verse_text in test_data['verses']: |
2962 | - importer.create_verse.assert_any_call(importer.create_book().id, '1', verse_tag, verse_text) |
2963 | + importer.create_verse.assert_any_call(importer.create_book().id, 1, verse_tag, verse_text) |
2964 | |
2965 | def test_file_import_milestone_tags(self): |
2966 | """ |
2967 | @@ -151,7 +504,7 @@ |
2968 | # THEN: The create_verse() method should have been called with each verse in the file. |
2969 | self.assertTrue(importer.create_verse.called) |
2970 | for verse_tag, verse_text in test_data['verses']: |
2971 | - importer.create_verse.assert_any_call(importer.create_book().id, '1', verse_tag, verse_text) |
2972 | + importer.create_verse.assert_any_call(importer.create_book().id, 1, verse_tag, verse_text) |
2973 | |
2974 | def test_file_import_empty_verse_tags(self): |
2975 | """ |
2976 | @@ -181,4 +534,4 @@ |
2977 | # THEN: The create_verse() method should have been called with each verse in the file. |
2978 | self.assertTrue(importer.create_verse.called) |
2979 | for verse_tag, verse_text in test_data['verses']: |
2980 | - importer.create_verse.assert_any_call(importer.create_book().id, '1', verse_tag, verse_text) |
2981 | + importer.create_verse.assert_any_call(importer.create_book().id, 1, verse_tag, verse_text) |
2982 | |
2983 | === modified file 'tests/functional/openlp_plugins/bibles/test_swordimport.py' |
2984 | --- tests/functional/openlp_plugins/bibles/test_swordimport.py 2016-08-09 20:45:25 +0000 |
2985 | +++ tests/functional/openlp_plugins/bibles/test_swordimport.py 2016-09-09 21:59:44 +0000 |
2986 | @@ -46,7 +46,7 @@ |
2987 | """ |
2988 | |
2989 | def setUp(self): |
2990 | - self.registry_patcher = patch('openlp.plugins.bibles.lib.db.Registry') |
2991 | + self.registry_patcher = patch('openlp.plugins.bibles.lib.bibleimport.Registry') |
2992 | self.registry_patcher.start() |
2993 | self.manager_patcher = patch('openlp.plugins.bibles.lib.db.Manager') |
2994 | self.manager_patcher.start() |
2995 | |
2996 | === modified file 'tests/functional/openlp_plugins/bibles/test_zefaniaimport.py' |
2997 | --- tests/functional/openlp_plugins/bibles/test_zefaniaimport.py 2016-08-09 20:45:25 +0000 |
2998 | +++ tests/functional/openlp_plugins/bibles/test_zefaniaimport.py 2016-09-09 21:59:44 +0000 |
2999 | @@ -41,15 +41,13 @@ |
3000 | """ |
3001 | |
3002 | def setUp(self): |
3003 | - self.registry_patcher = patch('openlp.plugins.bibles.lib.db.Registry') |
3004 | + self.registry_patcher = patch('openlp.plugins.bibles.lib.bibleimport.Registry') |
3005 | + self.addCleanup(self.registry_patcher.stop) |
3006 | self.registry_patcher.start() |
3007 | self.manager_patcher = patch('openlp.plugins.bibles.lib.db.Manager') |
3008 | + self.addCleanup(self.manager_patcher.stop) |
3009 | self.manager_patcher.start() |
3010 | |
3011 | - def tearDown(self): |
3012 | - self.registry_patcher.stop() |
3013 | - self.manager_patcher.stop() |
3014 | - |
3015 | def test_create_importer(self): |
3016 | """ |
3017 | Test creating an instance of the Zefania file importer |
3018 | @@ -90,7 +88,7 @@ |
3019 | # THEN: The create_verse() method should have been called with each verse in the file. |
3020 | self.assertTrue(importer.create_verse.called) |
3021 | for verse_tag, verse_text in test_data['verses']: |
3022 | - importer.create_verse.assert_any_call(importer.create_book().id, '1', verse_tag, verse_text) |
3023 | + importer.create_verse.assert_any_call(importer.create_book().id, 1, verse_tag, verse_text) |
3024 | importer.create_book.assert_any_call('Genesis', 1, 1) |
3025 | |
3026 | def test_file_import_no_book_name(self): |
3027 | @@ -120,5 +118,5 @@ |
3028 | # THEN: The create_verse() method should have been called with each verse in the file. |
3029 | self.assertTrue(importer.create_verse.called) |
3030 | for verse_tag, verse_text in test_data['verses']: |
3031 | - importer.create_verse.assert_any_call(importer.create_book().id, '1', verse_tag, verse_text) |
3032 | + importer.create_verse.assert_any_call(importer.create_book().id, 1, verse_tag, verse_text) |
3033 | importer.create_book.assert_any_call('Exodus', 2, 1) |
3034 | |
3035 | === modified file 'tests/resources/bibles/dk1933.json' |
3036 | --- tests/resources/bibles/dk1933.json 2014-08-24 14:40:45 +0000 |
3037 | +++ tests/resources/bibles/dk1933.json 2016-09-09 21:59:44 +0000 |
3038 | @@ -2,15 +2,15 @@ |
3039 | "book": "Genesis", |
3040 | "chapter": 1, |
3041 | "verses": [ |
3042 | - [ "1", "I Begyndelsen skabte Gud Himmelen og Jorden."], |
3043 | - [ "2", "Og Jorden var øde og tom, og der var Mørke over Verdensdybet. Men Guds Ånd svævede over Vandene." ], |
3044 | - [ "3", "Og Gud sagde: \"Der blive Lys!\" Og der blev Lys." ], |
3045 | - [ "4", "Og Gud så, at Lyset var godt, og Gud satte Skel mellem Lyset og Mørket," ], |
3046 | - [ "5", "og Gud kaldte Lyset Dag, og Mørket kaldte han Nat. Og det blev Aften, og det blev Morgen, første Dag." ], |
3047 | - [ "6", "Derpå sagde Gud: \"Der blive en Hvælving midt i Vandene til at skille Vandene ad!\"" ], |
3048 | - [ "7", "Og således skete det: Gud gjorde Hvælvingen og skilte Vandet under Hvælvingen fra Vandet over Hvælvingen;" ], |
3049 | - [ "8", "og Gud kaldte Hvælvingen Himmel. Og det blev Aften, og det blev Morgen, anden Dag." ], |
3050 | - [ "9", "Derpå sagde Gud: \"Vandet under Himmelen samle sig på eet Sted, så det faste Land kommer til Syne!\" Og således skete det;" ], |
3051 | - [ "10", "og Gud kaldte det faste Land Jord, og Stedet, hvor Vandet samlede sig, kaldte han Hav. Og Gud så, at det var godt." ] |
3052 | + [ 1, "I Begyndelsen skabte Gud Himmelen og Jorden."], |
3053 | + [ 2, "Og Jorden var øde og tom, og der var Mørke over Verdensdybet. Men Guds Ånd svævede over Vandene." ], |
3054 | + [ 3, "Og Gud sagde: \"Der blive Lys!\" Og der blev Lys." ], |
3055 | + [ 4, "Og Gud så, at Lyset var godt, og Gud satte Skel mellem Lyset og Mørket," ], |
3056 | + [ 5, "og Gud kaldte Lyset Dag, og Mørket kaldte han Nat. Og det blev Aften, og det blev Morgen, første Dag." ], |
3057 | + [ 6, "Derpå sagde Gud: \"Der blive en Hvælving midt i Vandene til at skille Vandene ad!\"" ], |
3058 | + [ 7, "Og således skete det: Gud gjorde Hvælvingen og skilte Vandet under Hvælvingen fra Vandet over Hvælvingen;" ], |
3059 | + [ 8, "og Gud kaldte Hvælvingen Himmel. Og det blev Aften, og det blev Morgen, anden Dag." ], |
3060 | + [ 9, "Derpå sagde Gud: \"Vandet under Himmelen samle sig på eet Sted, så det faste Land kommer til Syne!\" Og således skete det;" ], |
3061 | + [ 10, "og Gud kaldte det faste Land Jord, og Stedet, hvor Vandet samlede sig, kaldte han Hav. Og Gud så, at det var godt." ] |
3062 | ] |
3063 | } |
3064 | \ No newline at end of file |
3065 | |
3066 | === modified file 'tests/resources/bibles/kjv.json' |
3067 | --- tests/resources/bibles/kjv.json 2014-08-24 14:40:45 +0000 |
3068 | +++ tests/resources/bibles/kjv.json 2016-09-09 21:59:44 +0000 |
3069 | @@ -2,15 +2,15 @@ |
3070 | "book": "Genesis", |
3071 | "chapter": 1, |
3072 | "verses": [ |
3073 | - [ "1", "In the beginning God created the heaven and the earth."], |
3074 | - [ "2", "And the earth was without form, and void; and darkness was upon the face of the deep. And the Spirit of God moved upon the face of the waters." ], |
3075 | - [ "3", "And God said, Let there be light: and there was light." ], |
3076 | - [ "4", "And God saw the light, that it was good: and God divided the light from the darkness." ], |
3077 | - [ "5", "And God called the light Day, and the darkness he called Night. And the evening and the morning were the first day." ], |
3078 | - [ "6", "And God said, Let there be a firmament in the midst of the waters, and let it divide the waters from the waters." ], |
3079 | - [ "7", "And God made the firmament, and divided the waters which were under the firmament from the waters which were above the firmament: and it was so." ], |
3080 | - [ "8", "And God called the firmament Heaven. And the evening and the morning were the second day." ], |
3081 | - [ "9", "And God said, Let the waters under the heaven be gathered together unto one place, and let the dry land appear: and it was so." ], |
3082 | - [ "10", "And God called the dry land Earth; and the gathering together of the waters called he Seas: and God saw that it was good." ] |
3083 | + [ 1, "In the beginning God created the heaven and the earth."], |
3084 | + [ 2, "And the earth was without form, and void; and darkness was upon the face of the deep. And the Spirit of God moved upon the face of the waters." ], |
3085 | + [ 3, "And God said, Let there be light: and there was light." ], |
3086 | + [ 4, "And God saw the light, that it was good: and God divided the light from the darkness." ], |
3087 | + [ 5, "And God called the light Day, and the darkness he called Night. And the evening and the morning were the first day." ], |
3088 | + [ 6, "And God said, Let there be a firmament in the midst of the waters, and let it divide the waters from the waters." ], |
3089 | + [ 7, "And God made the firmament, and divided the waters which were under the firmament from the waters which were above the firmament: and it was so." ], |
3090 | + [ 8, "And God called the firmament Heaven. And the evening and the morning were the second day." ], |
3091 | + [ 9, "And God said, Let the waters under the heaven be gathered together unto one place, and let the dry land appear: and it was so." ], |
3092 | + [ 10, "And God called the dry land Earth; and the gathering together of the waters called he Seas: and God saw that it was good." ] |
3093 | ] |
3094 | } |
3095 | |
3096 | === modified file 'tests/resources/bibles/rst.json' |
3097 | --- tests/resources/bibles/rst.json 2015-02-02 20:40:31 +0000 |
3098 | +++ tests/resources/bibles/rst.json 2016-09-09 21:59:44 +0000 |
3099 | @@ -2,15 +2,15 @@ |
3100 | "book": "Exodus", |
3101 | "chapter": 1, |
3102 | "verses": [ |
3103 | - [ "1", "Вот имена сынов Израилевых, которые вошли в Египет с Иаковом, вошли каждый с домом своим:" ], |
3104 | - [ "2", "Рувим, Симеон, Левий и Иуда," ], |
3105 | - [ "3", "Иссахар, Завулон и Вениамин," ], |
3106 | - [ "4", "Дан и Неффалим, Гад и Асир." ], |
3107 | - [ "5", "Всех же душ, происшедших от чресл Иакова, было семьдесят, а Иосиф был [уже] в Египте." ], |
3108 | - [ "6", "И умер Иосиф и все братья его и весь род их;" ], |
3109 | - [ "7", "а сыны Израилевы расплодились и размножились, и возросли и усилились чрезвычайно, и наполнилась ими земля та." ], |
3110 | - [ "8", "И восстал в Египте новый царь, который не знал Иосифа," ], |
3111 | - [ "9", "и сказал народу своему: вот, народ сынов Израилевых многочислен и сильнее нас;" ], |
3112 | - [ "10", "перехитрим же его, чтобы он не размножался; иначе, когда случится война, соединится и он с нашими неприятелями, и вооружится против нас, и выйдет из земли [нашей]." ] |
3113 | + [ 1, "Вот имена сынов Израилевых, которые вошли в Египет с Иаковом, вошли каждый с домом своим:" ], |
3114 | + [ 2, "Рувим, Симеон, Левий и Иуда," ], |
3115 | + [ 3, "Иссахар, Завулон и Вениамин," ], |
3116 | + [ 4, "Дан и Неффалим, Гад и Асир." ], |
3117 | + [ 5, "Всех же душ, происшедших от чресл Иакова, было семьдесят, а Иосиф был [уже] в Египте." ], |
3118 | + [ 6, "И умер Иосиф и все братья его и весь род их;" ], |
3119 | + [ 7, "а сыны Израилевы расплодились и размножились, и возросли и усилились чрезвычайно, и наполнилась ими земля та." ], |
3120 | + [ 8, "И восстал в Египте новый царь, который не знал Иосифа," ], |
3121 | + [ 9, "и сказал народу своему: вот, народ сынов Израилевых многочислен и сильнее нас;" ], |
3122 | + [ 10, "перехитрим же его, чтобы он не размножался; иначе, когда случится война, соединится и он с нашими неприятелями, и вооружится против нас, и выйдет из земли [нашей]." ] |
3123 | ] |
3124 | } |
3125 | |
3126 | === modified file 'tests/resources/bibles/web.json' |
3127 | --- tests/resources/bibles/web.json 2014-08-24 14:40:45 +0000 |
3128 | +++ tests/resources/bibles/web.json 2016-09-09 21:59:44 +0000 |
3129 | @@ -2,15 +2,15 @@ |
3130 | "book": "Genesis", |
3131 | "chapter": "1", |
3132 | "verses": [ |
3133 | - [ "1", "In the beginning God created the heavens and the earth."], |
3134 | - [ "2", "Now the earth was formless and empty. Darkness was on the surface of the deep. God’s Spirit was hovering over the surface of the waters." ], |
3135 | - [ "3", "God said, “Let there be light,” and there was light." ], |
3136 | - [ "4", "God saw the light, and saw that it was good. God divided the light from the darkness." ], |
3137 | - [ "5", "God called the light “day,” and the darkness he called “night.” There was evening and there was morning, one day." ], |
3138 | - [ "6", "God said, “Let there be an expanse in the middle of the waters, and let it divide the waters from the waters.”" ], |
3139 | - [ "7", "God made the expanse, and divided the waters which were under the expanse from the waters which were above the expanse; and it was so." ], |
3140 | - [ "8", "God called the expanse “sky.” There was evening and there was morning, a second day." ], |
3141 | - [ "9", "God said, “Let the waters under the sky be gathered together to one place, and let the dry land appear;” and it was so." ], |
3142 | - [ "10", "God called the dry land “earth,” and the gathering together of the waters he called “seas.” God saw that it was good." ] |
3143 | + [ 1, "In the beginning God created the heavens and the earth."], |
3144 | + [ 2, "Now the earth was formless and empty. Darkness was on the surface of the deep. God’s Spirit was hovering over the surface of the waters." ], |
3145 | + [ 3, "God said, “Let there be light,” and there was light." ], |
3146 | + [ 4, "God saw the light, and saw that it was good. God divided the light from the darkness." ], |
3147 | + [ 5, "God called the light “day,” and the darkness he called “night.” There was evening and there was morning, one day." ], |
3148 | + [ 6, "God said, “Let there be an expanse in the middle of the waters, and let it divide the waters from the waters.”" ], |
3149 | + [ 7, "God made the expanse, and divided the waters which were under the expanse from the waters which were above the expanse; and it was so." ], |
3150 | + [ 8, "God called the expanse “sky.” There was evening and there was morning, a second day." ], |
3151 | + [ 9, "God said, “Let the waters under the sky be gathered together to one place, and let the dry land appear;” and it was so." ], |
3152 | + [ 10, "God called the dry land “earth,” and the gathering together of the waters he called “seas.” God saw that it was good." ] |
3153 | ] |
3154 | } |
Sorry one small change needed.