forked from openlp/openlp
"Fix slide order change when splitting custom slides. Fixes bug 1554748.
Fix EasyWorship import issues with missing verses and traceback on unknown chars. Fixes bug 1553922 and 1547234. Fix traceback in the bug-report dialog. Fixes bug 1554428. Fix weird test bug in test_pluginmanager.py. Fix traceback when searching for book that doesn't exists in second bible. Fixes bug 1553863. Set progress bar steps to number of chapters in zefania import. Fix song tag detection. Fixes bug 1549549. Fix a m..." bzr-revno: 2624 Fixes: https://launchpad.net/bugs/1547234, https://launchpad.net/bugs/1549549, https://launchpad.net/bugs/1553863, https://launchpad.net/bugs/1553922, https://launchpad.net/bugs/1554428, https://launchpad.net/bugs/1554748
This commit is contained in:
commit
07323e50a6
@ -180,11 +180,13 @@ class ExceptionForm(QtWidgets.QDialog, Ui_ExceptionDialog, RegistryProperties):
|
|||||||
if ':' in line:
|
if ':' in line:
|
||||||
exception = line.split('\n')[-1].split(':')[0]
|
exception = line.split('\n')[-1].split(':')[0]
|
||||||
subject = 'Bug report: %s in %s' % (exception, source)
|
subject = 'Bug report: %s in %s' % (exception, source)
|
||||||
mail_to_url = QtCore.QUrlQuery('mailto:bugs@openlp.org')
|
mail_urlquery = QtCore.QUrlQuery()
|
||||||
mail_to_url.addQueryItem('subject', subject)
|
mail_urlquery.addQueryItem('subject', subject)
|
||||||
mail_to_url.addQueryItem('body', self.report_text % content)
|
mail_urlquery.addQueryItem('body', self.report_text % content)
|
||||||
if self.file_attachment:
|
if self.file_attachment:
|
||||||
mail_to_url.addQueryItem('attach', self.file_attachment)
|
mail_urlquery.addQueryItem('attach', self.file_attachment)
|
||||||
|
mail_to_url = QtCore.QUrl('mailto:bugs@openlp.org')
|
||||||
|
mail_to_url.setQuery(mail_urlquery)
|
||||||
QtGui.QDesktopServices.openUrl(mail_to_url)
|
QtGui.QDesktopServices.openUrl(mail_to_url)
|
||||||
|
|
||||||
def on_description_updated(self):
|
def on_description_updated(self):
|
||||||
|
@ -504,7 +504,7 @@ class CWExtract(RegistryProperties):
|
|||||||
soup = get_soup_for_bible_ref(chapter_url)
|
soup = get_soup_for_bible_ref(chapter_url)
|
||||||
if not soup:
|
if not soup:
|
||||||
return None
|
return None
|
||||||
content = soup.find_all(('h4', {'class': 'small-header'}))
|
content = soup.find_all('h4', {'class': 'small-header'})
|
||||||
if not content:
|
if not content:
|
||||||
log.error('No books found in the Crosswalk response.')
|
log.error('No books found in the Crosswalk response.')
|
||||||
send_error_message('parse')
|
send_error_message('parse')
|
||||||
|
@ -764,6 +764,9 @@ class BibleMediaItem(MediaManagerItem):
|
|||||||
except IndexError:
|
except IndexError:
|
||||||
log.exception('The second_search_results does not have as many verses as the search_results.')
|
log.exception('The second_search_results does not have as many verses as the search_results.')
|
||||||
break
|
break
|
||||||
|
except TypeError:
|
||||||
|
log.exception('The second_search_results does not have this book.')
|
||||||
|
break
|
||||||
bible_text = '%s %d%s%d (%s, %s)' % (book, verse.chapter, verse_separator, verse.verse, version,
|
bible_text = '%s %d%s%d (%s, %s)' % (book, verse.chapter, verse_separator, verse.verse, version,
|
||||||
second_version)
|
second_version)
|
||||||
else:
|
else:
|
||||||
|
@ -70,7 +70,8 @@ class ZefaniaBible(BibleDB):
|
|||||||
log.error('Importing books from "%s" failed' % self.filename)
|
log.error('Importing books from "%s" failed' % self.filename)
|
||||||
return False
|
return False
|
||||||
self.save_meta('language_id', language_id)
|
self.save_meta('language_id', language_id)
|
||||||
num_books = int(zefania_bible_tree.xpath("count(//BIBLEBOOK)"))
|
num_books = int(zefania_bible_tree.xpath('count(//BIBLEBOOK)'))
|
||||||
|
self.wizard.progress_bar.setMaximum(int(zefania_bible_tree.xpath('count(//CHAPTER)')))
|
||||||
# Strip tags we don't use - keep content
|
# Strip tags we don't use - keep content
|
||||||
etree.strip_tags(zefania_bible_tree, ('STYLE', 'GRAM', 'NOTE', 'SUP', 'XREF'))
|
etree.strip_tags(zefania_bible_tree, ('STYLE', 'GRAM', 'NOTE', 'SUP', 'XREF'))
|
||||||
# Strip tags we don't use - remove content
|
# Strip tags we don't use - remove content
|
||||||
|
@ -198,6 +198,7 @@ class EditCustomForm(QtWidgets.QDialog, Ui_CustomEditDialog):
|
|||||||
# Insert all slides to make the old_slides list complete.
|
# Insert all slides to make the old_slides list complete.
|
||||||
for slide in slides:
|
for slide in slides:
|
||||||
old_slides.insert(old_row, slide)
|
old_slides.insert(old_row, slide)
|
||||||
|
old_row += 1
|
||||||
self.slide_list_view.addItems(old_slides)
|
self.slide_list_view.addItems(old_slides)
|
||||||
self.slide_list_view.repaint()
|
self.slide_list_view.repaint()
|
||||||
|
|
||||||
|
@ -256,6 +256,7 @@ class VerseType(object):
|
|||||||
for num, translation in enumerate(VerseType.translated_names):
|
for num, translation in enumerate(VerseType.translated_names):
|
||||||
if verse_name == translation.lower():
|
if verse_name == translation.lower():
|
||||||
return num
|
return num
|
||||||
|
return None
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_loose_input(verse_name, default=Other):
|
def from_loose_input(verse_name, default=Other):
|
||||||
@ -271,7 +272,7 @@ class VerseType(object):
|
|||||||
if verse_index is None:
|
if verse_index is None:
|
||||||
verse_index = VerseType.from_string(verse_name, default)
|
verse_index = VerseType.from_string(verse_name, default)
|
||||||
elif len(verse_name) == 1:
|
elif len(verse_name) == 1:
|
||||||
verse_index = VerseType.from_translated_tag(verse_name, default)
|
verse_index = VerseType.from_translated_tag(verse_name, None)
|
||||||
if verse_index is None:
|
if verse_index is None:
|
||||||
verse_index = VerseType.from_tag(verse_name, default)
|
verse_index = VerseType.from_tag(verse_name, default)
|
||||||
else:
|
else:
|
||||||
|
@ -289,40 +289,45 @@ class EasyWorshipSongImport(SongImport):
|
|||||||
for i in range(rec_count):
|
for i in range(rec_count):
|
||||||
if self.stop_import_flag:
|
if self.stop_import_flag:
|
||||||
break
|
break
|
||||||
raw_record = db_file.read(record_size)
|
try:
|
||||||
self.fields = self.record_structure.unpack(raw_record)
|
raw_record = db_file.read(record_size)
|
||||||
self.set_defaults()
|
self.fields = self.record_structure.unpack(raw_record)
|
||||||
self.title = self.get_field(fi_title).decode(self.encoding)
|
self.set_defaults()
|
||||||
# Get remaining fields.
|
self.title = self.get_field(fi_title).decode(self.encoding)
|
||||||
copy = self.get_field(fi_copy)
|
# Get remaining fields.
|
||||||
admin = self.get_field(fi_admin)
|
copy = self.get_field(fi_copy)
|
||||||
ccli = self.get_field(fi_ccli)
|
admin = self.get_field(fi_admin)
|
||||||
authors = self.get_field(fi_author)
|
ccli = self.get_field(fi_ccli)
|
||||||
words = self.get_field(fi_words)
|
authors = self.get_field(fi_author)
|
||||||
if copy:
|
words = self.get_field(fi_words)
|
||||||
self.copyright = copy.decode(self.encoding)
|
|
||||||
if admin:
|
|
||||||
if copy:
|
if copy:
|
||||||
self.copyright += ', '
|
self.copyright = copy.decode(self.encoding)
|
||||||
self.copyright += translate('SongsPlugin.EasyWorshipSongImport',
|
if admin:
|
||||||
'Administered by %s') % admin.decode(self.encoding)
|
if copy:
|
||||||
if ccli:
|
self.copyright += ', '
|
||||||
self.ccli_number = ccli.decode(self.encoding)
|
self.copyright += translate('SongsPlugin.EasyWorshipSongImport',
|
||||||
if authors:
|
'Administered by %s') % admin.decode(self.encoding)
|
||||||
authors = authors.decode(self.encoding)
|
if ccli:
|
||||||
else:
|
self.ccli_number = ccli.decode(self.encoding)
|
||||||
authors = ''
|
if authors:
|
||||||
# Set the SongImport object members.
|
authors = authors.decode(self.encoding)
|
||||||
self.set_song_import_object(authors, words)
|
else:
|
||||||
if self.stop_import_flag:
|
authors = ''
|
||||||
break
|
# Set the SongImport object members.
|
||||||
if self.entry_error_log:
|
self.set_song_import_object(authors, words)
|
||||||
|
if self.stop_import_flag:
|
||||||
|
break
|
||||||
|
if self.entry_error_log:
|
||||||
|
self.log_error(self.import_source,
|
||||||
|
translate('SongsPlugin.EasyWorshipSongImport', '"%s" could not be imported. %s')
|
||||||
|
% (self.title, self.entry_error_log))
|
||||||
|
self.entry_error_log = ''
|
||||||
|
elif not self.finish():
|
||||||
|
self.log_error(self.import_source)
|
||||||
|
except Exception as e:
|
||||||
self.log_error(self.import_source,
|
self.log_error(self.import_source,
|
||||||
translate('SongsPlugin.EasyWorshipSongImport', '"%s" could not be imported. %s')
|
translate('SongsPlugin.EasyWorshipSongImport', '"%s" could not be imported. %s')
|
||||||
% (self.title, self.entry_error_log))
|
% (self.title, e))
|
||||||
self.entry_error_log = ''
|
|
||||||
elif not self.finish():
|
|
||||||
self.log_error(self.import_source)
|
|
||||||
db_file.close()
|
db_file.close()
|
||||||
self.memo_file.close()
|
self.memo_file.close()
|
||||||
|
|
||||||
@ -368,7 +373,7 @@ class EasyWorshipSongImport(SongImport):
|
|||||||
first_line_is_tag = False
|
first_line_is_tag = False
|
||||||
# EW tags: verse, chorus, pre-chorus, bridge, tag,
|
# EW tags: verse, chorus, pre-chorus, bridge, tag,
|
||||||
# intro, ending, slide
|
# intro, ending, slide
|
||||||
for tag in VerseType.tags + ['tag', 'slide']:
|
for tag in VerseType.names + ['tag', 'slide', 'end']:
|
||||||
tag = tag.lower()
|
tag = tag.lower()
|
||||||
ew_tag = verse_split[0].strip().lower()
|
ew_tag = verse_split[0].strip().lower()
|
||||||
if ew_tag.startswith(tag):
|
if ew_tag.startswith(tag):
|
||||||
@ -390,6 +395,9 @@ class EasyWorshipSongImport(SongImport):
|
|||||||
if not number_found:
|
if not number_found:
|
||||||
verse_type += '1'
|
verse_type += '1'
|
||||||
break
|
break
|
||||||
|
# If the verse only consist of the tag-line, add an empty line to create an empty slide
|
||||||
|
if first_line_is_tag and len(verse_split) == 1:
|
||||||
|
verse_split.append("")
|
||||||
self.add_verse(verse_split[-1].strip() if first_line_is_tag else verse, verse_type)
|
self.add_verse(verse_split[-1].strip() if first_line_is_tag else verse, verse_type)
|
||||||
if len(self.comments) > 5:
|
if len(self.comments) > 5:
|
||||||
self.comments += str(translate('SongsPlugin.EasyWorshipSongImport',
|
self.comments += str(translate('SongsPlugin.EasyWorshipSongImport',
|
||||||
|
@ -371,7 +371,7 @@ class SongImport(QtCore.QObject):
|
|||||||
song_book = self.manager.get_object_filtered(Book, Book.name == self.song_book_name)
|
song_book = self.manager.get_object_filtered(Book, Book.name == self.song_book_name)
|
||||||
if song_book is None:
|
if song_book is None:
|
||||||
song_book = Book.populate(name=self.song_book_name, publisher=self.song_book_pub)
|
song_book = Book.populate(name=self.song_book_name, publisher=self.song_book_pub)
|
||||||
song.book = song_book
|
song.add_songbook_entry(song_book, song.song_number)
|
||||||
for topic_text in self.topics:
|
for topic_text in self.topics:
|
||||||
if not topic_text:
|
if not topic_text:
|
||||||
continue
|
continue
|
||||||
|
@ -26,12 +26,12 @@ import sys
|
|||||||
from PyQt5 import QtWidgets
|
from PyQt5 import QtWidgets
|
||||||
|
|
||||||
if sys.version_info[1] >= 3:
|
if sys.version_info[1] >= 3:
|
||||||
from unittest.mock import ANY, MagicMock, patch, mock_open, call
|
from unittest.mock import ANY, MagicMock, patch, mock_open, call, PropertyMock
|
||||||
else:
|
else:
|
||||||
from mock import ANY, MagicMock, patch, mock_open, call
|
from mock import ANY, MagicMock, patch, mock_open, call, PropertyMock
|
||||||
|
|
||||||
# Only one QApplication can be created. Use QtWidgets.QApplication.instance() when you need to "create" a QApplication.
|
# Only one QApplication can be created. Use QtWidgets.QApplication.instance() when you need to "create" a QApplication.
|
||||||
application = QtWidgets.QApplication([])
|
application = QtWidgets.QApplication([])
|
||||||
application.setApplicationName('OpenLP')
|
application.setApplicationName('OpenLP')
|
||||||
|
|
||||||
__all__ = ['ANY', 'MagicMock', 'patch', 'mock_open', 'call', 'application']
|
__all__ = ['ANY', 'MagicMock', 'patch', 'mock_open', 'call', 'application', 'PropertyMock']
|
||||||
|
@ -26,7 +26,7 @@ from unittest import TestCase
|
|||||||
|
|
||||||
from openlp.plugins.songs.lib import VerseType, clean_string, clean_title, strip_rtf
|
from openlp.plugins.songs.lib import VerseType, clean_string, clean_title, strip_rtf
|
||||||
from openlp.plugins.songs.lib.songcompare import songs_probably_equal, _remove_typos, _op_length
|
from openlp.plugins.songs.lib.songcompare import songs_probably_equal, _remove_typos, _op_length
|
||||||
from tests.functional import patch, MagicMock
|
from tests.functional import patch, MagicMock, PropertyMock
|
||||||
|
|
||||||
|
|
||||||
class TestLib(TestCase):
|
class TestLib(TestCase):
|
||||||
@ -477,3 +477,27 @@ class TestVerseType(TestCase):
|
|||||||
|
|
||||||
# THEN: The result should be None
|
# THEN: The result should be None
|
||||||
self.assertIsNone(result, 'The result should be None, but was "%s"' % result)
|
self.assertIsNone(result, 'The result should be None, but was "%s"' % result)
|
||||||
|
|
||||||
|
@patch('openlp.plugins.songs.lib.VerseType.translated_tags', new_callable=PropertyMock, return_value=['x'])
|
||||||
|
def from_loose_input_with_invalid_input_test(self, mocked_translated_tags):
|
||||||
|
"""
|
||||||
|
Test that the from_loose_input() method returns a sane default when passed an invalid tag and None as default.
|
||||||
|
"""
|
||||||
|
# GIVEN: A mocked VerseType.translated_tags
|
||||||
|
# WHEN: We run the from_loose_input() method with an invalid verse type, we get the specified default back
|
||||||
|
result = VerseType.from_loose_input('m', None)
|
||||||
|
|
||||||
|
# THEN: The result should be None
|
||||||
|
self.assertIsNone(result, 'The result should be None, but was "%s"' % result)
|
||||||
|
|
||||||
|
@patch('openlp.plugins.songs.lib.VerseType.translated_tags', new_callable=PropertyMock, return_value=['x'])
|
||||||
|
def from_loose_input_with_valid_input_test(self, mocked_translated_tags):
|
||||||
|
"""
|
||||||
|
Test that the from_loose_input() method returns valid output on valid input.
|
||||||
|
"""
|
||||||
|
# GIVEN: A mocked VerseType.translated_tags
|
||||||
|
# WHEN: We run the from_loose_input() method with a valid verse type, we get the expected VerseType back
|
||||||
|
result = VerseType.from_loose_input('v')
|
||||||
|
|
||||||
|
# THEN: The result should be a Verse
|
||||||
|
self.assertEqual(result, VerseType.Verse, 'The result should be a verse, but was "%s"' % result)
|
||||||
|
@ -32,7 +32,7 @@ from PyQt5 import QtWidgets
|
|||||||
|
|
||||||
from openlp.core.common import Registry, Settings
|
from openlp.core.common import Registry, Settings
|
||||||
from openlp.core.lib.pluginmanager import PluginManager
|
from openlp.core.lib.pluginmanager import PluginManager
|
||||||
from tests.interfaces import MagicMock
|
from tests.interfaces import MagicMock, patch
|
||||||
from tests.helpers.testmixin import TestMixin
|
from tests.helpers.testmixin import TestMixin
|
||||||
|
|
||||||
|
|
||||||
@ -45,13 +45,12 @@ class TestPluginManager(TestCase, TestMixin):
|
|||||||
"""
|
"""
|
||||||
Some pre-test setup required.
|
Some pre-test setup required.
|
||||||
"""
|
"""
|
||||||
Settings.setDefaultFormat(Settings.IniFormat)
|
self.setup_application()
|
||||||
self.build_settings()
|
self.build_settings()
|
||||||
self.temp_dir = mkdtemp('openlp')
|
self.temp_dir = mkdtemp('openlp')
|
||||||
Settings().setValue('advanced/data path', self.temp_dir)
|
Settings().setValue('advanced/data path', self.temp_dir)
|
||||||
Registry.create()
|
Registry.create()
|
||||||
Registry().register('service_list', MagicMock())
|
Registry().register('service_list', MagicMock())
|
||||||
self.setup_application()
|
|
||||||
self.main_window = QtWidgets.QMainWindow()
|
self.main_window = QtWidgets.QMainWindow()
|
||||||
Registry().register('main_window', self.main_window)
|
Registry().register('main_window', self.main_window)
|
||||||
|
|
||||||
@ -64,7 +63,13 @@ class TestPluginManager(TestCase, TestMixin):
|
|||||||
gc.collect()
|
gc.collect()
|
||||||
shutil.rmtree(self.temp_dir)
|
shutil.rmtree(self.temp_dir)
|
||||||
|
|
||||||
def find_plugins_test(self):
|
@patch('openlp.plugins.songusage.lib.db.init_schema')
|
||||||
|
@patch('openlp.plugins.songs.lib.db.init_schema')
|
||||||
|
@patch('openlp.plugins.images.lib.db.init_schema')
|
||||||
|
@patch('openlp.plugins.custom.lib.db.init_schema')
|
||||||
|
@patch('openlp.plugins.alerts.lib.db.init_schema')
|
||||||
|
@patch('openlp.plugins.bibles.lib.db.init_schema')
|
||||||
|
def find_plugins_test(self, mocked_is1, mocked_is2, mocked_is3, mocked_is4, mocked_is5, mocked_is6):
|
||||||
"""
|
"""
|
||||||
Test the find_plugins() method to ensure it imports the correct plugins
|
Test the find_plugins() method to ensure it imports the correct plugins
|
||||||
"""
|
"""
|
||||||
|
@ -128,3 +128,19 @@ class TestEditCustomForm(TestCase, TestMixin):
|
|||||||
# THEN: The validate method should have returned False.
|
# THEN: The validate method should have returned False.
|
||||||
assert not result, 'The _validate() method should have retured False'
|
assert not result, 'The _validate() method should have retured False'
|
||||||
mocked_critical_error_message_box.assert_called_with(message='You need to add at least one slide.')
|
mocked_critical_error_message_box.assert_called_with(message='You need to add at least one slide.')
|
||||||
|
|
||||||
|
def update_slide_list_test(self):
|
||||||
|
"""
|
||||||
|
Test the update_slide_list() method
|
||||||
|
"""
|
||||||
|
# GIVEN: Mocked slide_list_view with a slide with 3 lines
|
||||||
|
self.form.slide_list_view = MagicMock()
|
||||||
|
self.form.slide_list_view.count.return_value = 1
|
||||||
|
self.form.slide_list_view.currentRow.return_value = 0
|
||||||
|
self.form.slide_list_view.item.return_value = MagicMock(return_value='1st Slide\n2nd Slide\n3rd Slide')
|
||||||
|
|
||||||
|
# WHEN: updating the slide by splitting the lines into slides
|
||||||
|
self.form.update_slide_list(['1st Slide', '2nd Slide', '3rd Slide'])
|
||||||
|
|
||||||
|
# THEN: The slides should be created in correct order
|
||||||
|
self.form.slide_list_view.addItems.assert_called_with(['1st Slide', '2nd Slide', '3rd Slide'])
|
||||||
|
Loading…
Reference in New Issue
Block a user