forked from openlp/openlp
Fix bug #1423699 so that you're not logged out when you want to import more songs.
Fixes: https://launchpad.net/bugs/1423699
This commit is contained in:
parent
b65e592df9
commit
7d7fec194e
@ -40,3 +40,5 @@ __pycache__
|
||||
# Rejected diff's
|
||||
*.rej
|
||||
*.~\?~
|
||||
.coverage
|
||||
cover
|
||||
|
@ -192,7 +192,7 @@ class SongSelectForm(QtGui.QDialog, Ui_SongSelectDialog):
|
||||
self, translate('SongsPlugin.SongSelectForm', 'Incomplete song'),
|
||||
translate('SongsPlugin.SongSelectForm', 'This song is missing some information, like the lyrics, '
|
||||
'and cannot be imported.'),
|
||||
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok), QtGui.QMessageBox.OK)
|
||||
QtGui.QMessageBox.StandardButtons(QtGui.QMessageBox.Ok), QtGui.QMessageBox.Ok)
|
||||
self.stacked_widget.setCurrentIndex(1)
|
||||
return
|
||||
# Update the UI
|
||||
@ -367,15 +367,11 @@ class SongSelectForm(QtGui.QDialog, Ui_SongSelectDialog):
|
||||
Import a song from SongSelect.
|
||||
"""
|
||||
self.song_select_importer.save_song(self.song)
|
||||
question_dialog = QtGui.QMessageBox()
|
||||
question_dialog.setWindowTitle(translate('SongsPlugin.SongSelectForm', 'Song Imported'))
|
||||
question_dialog.setText(translate('SongsPlugin.SongSelectForm', 'Your song has been imported, would you like '
|
||||
'to exit now, or import more songs?'))
|
||||
question_dialog.addButton(QtGui.QPushButton(translate('SongsPlugin.SongSelectForm', 'Import More Songs')),
|
||||
QtGui.QMessageBox.YesRole)
|
||||
question_dialog.addButton(QtGui.QPushButton(translate('SongsPlugin.SongSelectForm', 'Exit Now')),
|
||||
QtGui.QMessageBox.NoRole)
|
||||
if question_dialog.exec_() == QtGui.QMessageBox.Yes:
|
||||
if QtGui.QMessageBox.question(self, translate('SongsPlugin.SongSelectForm', 'Song Imported'),
|
||||
translate('SongsPlugin.SongSelectForm', 'Your song has been imported, would you '
|
||||
'like to import more songs?'),
|
||||
QtGui.QMessageBox.Yes | QtGui.QMessageBox.No,
|
||||
QtGui.QMessageBox.Yes) == QtGui.QMessageBox.Yes:
|
||||
self.on_back_button_clicked()
|
||||
else:
|
||||
self.application.process_events()
|
||||
|
@ -23,29 +23,31 @@
|
||||
This module contains tests for the CCLI SongSelect importer.
|
||||
"""
|
||||
import os
|
||||
|
||||
from unittest import TestCase
|
||||
from urllib.error import URLError
|
||||
from tests.functional import MagicMock, patch, call
|
||||
from tests.helpers.testmixin import TestMixin
|
||||
|
||||
from PyQt4 import QtGui
|
||||
|
||||
from openlp.core import Registry
|
||||
from openlp.plugins.songs.forms.songselectform import SongSelectForm
|
||||
from openlp.plugins.songs.lib import Author, Song, VerseType
|
||||
from openlp.plugins.songs.forms.songselectform import SongSelectForm, SearchWorker
|
||||
from openlp.plugins.songs.lib import Song
|
||||
from openlp.plugins.songs.lib.songselect import SongSelectImport, LOGOUT_URL, BASE_URL
|
||||
from openlp.plugins.songs.lib.importers.cclifile import CCLIFileImport
|
||||
|
||||
from tests.functional import MagicMock, patch, call
|
||||
from tests.helpers.testmixin import TestMixin
|
||||
|
||||
|
||||
class TestSongSelectImport(TestCase, TestMixin):
|
||||
"""
|
||||
Test the :class:`~openlp.plugins.songs.lib.songselect.SongSelectImport` class
|
||||
"""
|
||||
def constructor_test(self):
|
||||
@patch('openlp.plugins.songs.lib.songselect.build_opener')
|
||||
def constructor_test(self, mocked_build_opener):
|
||||
"""
|
||||
Test that constructing a basic SongSelectImport object works correctly
|
||||
"""
|
||||
# GIVEN: The SongSelectImporter class and a mocked out build_opener
|
||||
with patch('openlp.plugins.songs.lib.songselect.build_opener') as mocked_build_opener:
|
||||
# WHEN: An object is instantiated
|
||||
importer = SongSelectImport(None)
|
||||
|
||||
@ -55,13 +57,13 @@ class TestSongSelectImport(TestCase, TestMixin):
|
||||
self.assertIsNotNone(importer.opener, 'There should be a valid opener object')
|
||||
self.assertEqual(1, mocked_build_opener.call_count, 'The build_opener method should have been called once')
|
||||
|
||||
def login_fails_test(self):
|
||||
@patch('openlp.plugins.songs.lib.songselect.build_opener')
|
||||
@patch('openlp.plugins.songs.lib.songselect.BeautifulSoup')
|
||||
def login_fails_test(self, MockedBeautifulSoup, mocked_build_opener):
|
||||
"""
|
||||
Test that when logging in to SongSelect fails, the login method returns False
|
||||
"""
|
||||
# GIVEN: A bunch of mocked out stuff and an importer object
|
||||
with patch('openlp.plugins.songs.lib.songselect.build_opener') as mocked_build_opener, \
|
||||
patch('openlp.plugins.songs.lib.songselect.BeautifulSoup') as MockedBeautifulSoup:
|
||||
mocked_opener = MagicMock()
|
||||
mocked_build_opener.return_value = mocked_opener
|
||||
mocked_login_page = MagicMock()
|
||||
@ -79,13 +81,13 @@ class TestSongSelectImport(TestCase, TestMixin):
|
||||
self.assertEqual(2, mocked_opener.open.call_count, 'opener should have been called twice')
|
||||
self.assertFalse(result, 'The login method should have returned False')
|
||||
|
||||
def login_succeeds_test(self):
|
||||
@patch('openlp.plugins.songs.lib.songselect.build_opener')
|
||||
@patch('openlp.plugins.songs.lib.songselect.BeautifulSoup')
|
||||
def login_succeeds_test(self, MockedBeautifulSoup, mocked_build_opener):
|
||||
"""
|
||||
Test that when logging in to SongSelect succeeds, the login method returns True
|
||||
"""
|
||||
# GIVEN: A bunch of mocked out stuff and an importer object
|
||||
with patch('openlp.plugins.songs.lib.songselect.build_opener') as mocked_build_opener, \
|
||||
patch('openlp.plugins.songs.lib.songselect.BeautifulSoup') as MockedBeautifulSoup:
|
||||
mocked_opener = MagicMock()
|
||||
mocked_build_opener.return_value = mocked_opener
|
||||
mocked_login_page = MagicMock()
|
||||
@ -103,12 +105,12 @@ class TestSongSelectImport(TestCase, TestMixin):
|
||||
self.assertEqual(2, mocked_opener.open.call_count, 'opener should have been called twice')
|
||||
self.assertTrue(result, 'The login method should have returned True')
|
||||
|
||||
def logout_test(self):
|
||||
@patch('openlp.plugins.songs.lib.songselect.build_opener')
|
||||
def logout_test(self, mocked_build_opener):
|
||||
"""
|
||||
Test that when the logout method is called, it logs the user out of SongSelect
|
||||
"""
|
||||
# GIVEN: A bunch of mocked out stuff and an importer object
|
||||
with patch('openlp.plugins.songs.lib.songselect.build_opener') as mocked_build_opener:
|
||||
mocked_opener = MagicMock()
|
||||
mocked_build_opener.return_value = mocked_opener
|
||||
importer = SongSelectImport(None)
|
||||
@ -120,13 +122,13 @@ class TestSongSelectImport(TestCase, TestMixin):
|
||||
self.assertEqual(1, mocked_opener.open.call_count, 'opener should have been called once')
|
||||
mocked_opener.open.assert_called_with(LOGOUT_URL)
|
||||
|
||||
def search_returns_no_results_test(self):
|
||||
@patch('openlp.plugins.songs.lib.songselect.build_opener')
|
||||
@patch('openlp.plugins.songs.lib.songselect.BeautifulSoup')
|
||||
def search_returns_no_results_test(self, MockedBeautifulSoup, mocked_build_opener):
|
||||
"""
|
||||
Test that when the search finds no results, it simply returns an empty list
|
||||
"""
|
||||
# GIVEN: A bunch of mocked out stuff and an importer object
|
||||
with patch('openlp.plugins.songs.lib.songselect.build_opener') as mocked_build_opener, \
|
||||
patch('openlp.plugins.songs.lib.songselect.BeautifulSoup') as MockedBeautifulSoup:
|
||||
mocked_opener = MagicMock()
|
||||
mocked_build_opener.return_value = mocked_opener
|
||||
mocked_results_page = MagicMock()
|
||||
@ -145,13 +147,13 @@ class TestSongSelectImport(TestCase, TestMixin):
|
||||
mocked_results_page.find_all.assert_called_with('li', 'result pane')
|
||||
self.assertEqual([], results, 'The search method should have returned an empty list')
|
||||
|
||||
def search_returns_two_results_test(self):
|
||||
@patch('openlp.plugins.songs.lib.songselect.build_opener')
|
||||
@patch('openlp.plugins.songs.lib.songselect.BeautifulSoup')
|
||||
def search_returns_two_results_test(self, MockedBeautifulSoup, mocked_build_opener):
|
||||
"""
|
||||
Test that when the search finds 2 results, it simply returns a list with 2 results
|
||||
"""
|
||||
# GIVEN: A bunch of mocked out stuff and an importer object
|
||||
with patch('openlp.plugins.songs.lib.songselect.build_opener') as mocked_build_opener, \
|
||||
patch('openlp.plugins.songs.lib.songselect.BeautifulSoup') as MockedBeautifulSoup:
|
||||
# first search result
|
||||
mocked_result1 = MagicMock()
|
||||
mocked_result1.find.side_effect = [MagicMock(string='Title 1'), {'href': '/url1'}]
|
||||
@ -183,13 +185,13 @@ class TestSongSelectImport(TestCase, TestMixin):
|
||||
]
|
||||
self.assertListEqual(expected_list, results, 'The search method should have returned two songs')
|
||||
|
||||
def search_reaches_max_results_test(self):
|
||||
@patch('openlp.plugins.songs.lib.songselect.build_opener')
|
||||
@patch('openlp.plugins.songs.lib.songselect.BeautifulSoup')
|
||||
def search_reaches_max_results_test(self, MockedBeautifulSoup, mocked_build_opener):
|
||||
"""
|
||||
Test that when the search finds MAX (2) results, it simply returns a list with those (2)
|
||||
"""
|
||||
# GIVEN: A bunch of mocked out stuff and an importer object
|
||||
with patch('openlp.plugins.songs.lib.songselect.build_opener') as mocked_build_opener, \
|
||||
patch('openlp.plugins.songs.lib.songselect.BeautifulSoup') as MockedBeautifulSoup:
|
||||
# first search result
|
||||
mocked_result1 = MagicMock()
|
||||
mocked_result1.find.side_effect = [MagicMock(string='Title 1'), {'href': '/url1'}]
|
||||
@ -223,12 +225,12 @@ class TestSongSelectImport(TestCase, TestMixin):
|
||||
{'title': 'Title 2', 'authors': ['Author 2-1', 'Author 2-2'], 'link': BASE_URL + '/url2'}]
|
||||
self.assertListEqual(expected_list, results, 'The search method should have returned two songs')
|
||||
|
||||
def get_song_page_raises_exception_test(self):
|
||||
@patch('openlp.plugins.songs.lib.songselect.build_opener')
|
||||
def get_song_page_raises_exception_test(self, mocked_build_opener):
|
||||
"""
|
||||
Test that when BeautifulSoup gets a bad song page the get_song() method returns None
|
||||
"""
|
||||
# GIVEN: A bunch of mocked out stuff and an importer object
|
||||
with patch('openlp.plugins.songs.lib.songselect.build_opener') as mocked_build_opener:
|
||||
mocked_opener = MagicMock()
|
||||
mocked_build_opener.return_value = mocked_opener
|
||||
mocked_opener.open.read.side_effect = URLError('[Errno -2] Name or service not known')
|
||||
@ -242,13 +244,13 @@ class TestSongSelectImport(TestCase, TestMixin):
|
||||
mocked_callback.assert_called_with()
|
||||
self.assertIsNone(result, 'The get_song() method should have returned None')
|
||||
|
||||
def get_song_lyrics_raise_exception_test(self):
|
||||
@patch('openlp.plugins.songs.lib.songselect.build_opener')
|
||||
@patch('openlp.plugins.songs.lib.songselect.BeautifulSoup')
|
||||
def get_song_lyrics_raise_exception_test(self, MockedBeautifulSoup, mocked_build_opener):
|
||||
"""
|
||||
Test that when BeautifulSoup gets a bad lyrics page the get_song() method returns None
|
||||
"""
|
||||
# GIVEN: A bunch of mocked out stuff and an importer object
|
||||
with patch('openlp.plugins.songs.lib.songselect.build_opener'), \
|
||||
patch('openlp.plugins.songs.lib.songselect.BeautifulSoup') as MockedBeautifulSoup:
|
||||
MockedBeautifulSoup.side_effect = [None, TypeError('Test Error')]
|
||||
mocked_callback = MagicMock()
|
||||
importer = SongSelectImport(None)
|
||||
@ -260,13 +262,13 @@ class TestSongSelectImport(TestCase, TestMixin):
|
||||
self.assertEqual(2, mocked_callback.call_count, 'The callback should have been called twice')
|
||||
self.assertIsNone(result, 'The get_song() method should have returned None')
|
||||
|
||||
def get_song_test(self):
|
||||
@patch('openlp.plugins.songs.lib.songselect.build_opener')
|
||||
@patch('openlp.plugins.songs.lib.songselect.BeautifulSoup')
|
||||
def get_song_test(self, MockedBeautifulSoup, mocked_build_opener):
|
||||
"""
|
||||
Test that the get_song() method returns the correct song details
|
||||
"""
|
||||
# GIVEN: A bunch of mocked out stuff and an importer object
|
||||
with patch('openlp.plugins.songs.lib.songselect.build_opener'), \
|
||||
patch('openlp.plugins.songs.lib.songselect.BeautifulSoup') as MockedBeautifulSoup:
|
||||
mocked_song_page = MagicMock()
|
||||
mocked_copyright = MagicMock()
|
||||
mocked_copyright.find_all.return_value = [MagicMock(string='Copyright 1'), MagicMock(string='Copyright 2')]
|
||||
@ -308,13 +310,13 @@ class TestSongSelectImport(TestCase, TestMixin):
|
||||
self.assertIn('verses', result, 'The returned song should have verses')
|
||||
self.assertEqual(3, len(result['verses']), 'Three verses should have been returned')
|
||||
|
||||
def save_song_new_author_test(self):
|
||||
@patch('openlp.plugins.songs.lib.songselect.clean_song')
|
||||
@patch('openlp.plugins.songs.lib.songselect.Author')
|
||||
def save_song_new_author_test(self, MockedAuthor, mocked_clean_song):
|
||||
"""
|
||||
Test that saving a song with a new author performs the correct actions
|
||||
"""
|
||||
# GIVEN: A song to save, and some mocked out objects
|
||||
with patch('openlp.plugins.songs.lib.songselect.clean_song') as mocked_clean_song, \
|
||||
patch('openlp.plugins.songs.lib.songselect.Author') as MockedAuthor:
|
||||
song_dict = {
|
||||
'title': 'Arky Arky',
|
||||
'authors': ['Public Domain'],
|
||||
@ -344,13 +346,13 @@ class TestSongSelectImport(TestCase, TestMixin):
|
||||
display_name='Public Domain')
|
||||
self.assertEqual(1, len(result.authors_songs), 'There should only be one author')
|
||||
|
||||
def save_song_existing_author_test(self):
|
||||
@patch('openlp.plugins.songs.lib.songselect.clean_song')
|
||||
@patch('openlp.plugins.songs.lib.songselect.Author')
|
||||
def save_song_existing_author_test(self, MockedAuthor, mocked_clean_song):
|
||||
"""
|
||||
Test that saving a song with an existing author performs the correct actions
|
||||
"""
|
||||
# GIVEN: A song to save, and some mocked out objects
|
||||
with patch('openlp.plugins.songs.lib.songselect.clean_song') as mocked_clean_song, \
|
||||
patch('openlp.plugins.songs.lib.songselect.Author') as MockedAuthor:
|
||||
song_dict = {
|
||||
'title': 'Arky Arky',
|
||||
'authors': ['Public Domain'],
|
||||
@ -409,14 +411,14 @@ class TestSongSelectForm(TestCase, TestMixin):
|
||||
self.assertEqual(mocked_plugin, ssform.plugin, 'The correct plugin should have been assigned')
|
||||
self.assertEqual(mocked_db_manager, ssform.db_manager, 'The correct db_manager should have been assigned')
|
||||
|
||||
def login_fails_test(self):
|
||||
@patch('openlp.plugins.songs.forms.songselectform.SongSelectImport')
|
||||
@patch('openlp.plugins.songs.forms.songselectform.QtGui.QMessageBox.critical')
|
||||
@patch('openlp.plugins.songs.forms.songselectform.translate')
|
||||
def login_fails_test(self, mocked_translate, mocked_critical, MockedSongSelectImport):
|
||||
"""
|
||||
Test that when the login fails, the form returns to the correct state
|
||||
"""
|
||||
# GIVEN: A valid SongSelectForm with a mocked out SongSelectImport, and a bunch of mocked out controls
|
||||
with patch('openlp.plugins.songs.forms.songselectform.SongSelectImport') as MockedSongSelectImport, \
|
||||
patch('openlp.plugins.songs.forms.songselectform.QtGui.QMessageBox.critical') as mocked_critical, \
|
||||
patch('openlp.plugins.songs.forms.songselectform.translate') as mocked_translate:
|
||||
mocked_song_select_import = MagicMock()
|
||||
mocked_song_select_import.login.return_value = False
|
||||
MockedSongSelectImport.return_value = mocked_song_select_import
|
||||
@ -463,6 +465,166 @@ class TestSongSelectForm(TestCase, TestMixin):
|
||||
'perhaps your username or password is '
|
||||
'incorrect?')
|
||||
|
||||
@patch('openlp.plugins.songs.forms.songselectform.QtGui.QMessageBox.question')
|
||||
@patch('openlp.plugins.songs.forms.songselectform.translate')
|
||||
def on_import_yes_clicked_test(self, mocked_translate, mocked_question):
|
||||
"""
|
||||
Test that when a song is imported and the user clicks the "yes" button, the UI goes back to the previous page
|
||||
"""
|
||||
# GIVEN: A valid SongSelectForm with a mocked out QMessageBox.question() method
|
||||
mocked_translate.side_effect = lambda *args: args[1]
|
||||
mocked_question.return_value = QtGui.QMessageBox.Yes
|
||||
ssform = SongSelectForm(None, MagicMock(), MagicMock())
|
||||
mocked_song_select_importer = MagicMock()
|
||||
ssform.song_select_importer = mocked_song_select_importer
|
||||
ssform.song = None
|
||||
|
||||
# WHEN: The import button is clicked, and the user clicks Yes
|
||||
with patch.object(ssform, 'on_back_button_clicked') as mocked_on_back_button_clicked:
|
||||
ssform.on_import_button_clicked()
|
||||
|
||||
# THEN: The on_back_button_clicked() method should have been called
|
||||
mocked_song_select_importer.save_song.assert_called_with(None)
|
||||
mocked_question.assert_called_with(ssform, 'Song Imported',
|
||||
'Your song has been imported, would you like to import more songs?',
|
||||
QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.Yes)
|
||||
mocked_on_back_button_clicked.assert_called_with()
|
||||
|
||||
@patch('openlp.plugins.songs.forms.songselectform.QtGui.QMessageBox.question')
|
||||
@patch('openlp.plugins.songs.forms.songselectform.translate')
|
||||
def on_import_no_clicked_test(self, mocked_translate, mocked_question):
|
||||
"""
|
||||
Test that when a song is imported and the user clicks the "no" button, the UI exits
|
||||
"""
|
||||
# GIVEN: A valid SongSelectForm with a mocked out QMessageBox.question() method
|
||||
mocked_translate.side_effect = lambda *args: args[1]
|
||||
mocked_question.return_value = QtGui.QMessageBox.No
|
||||
ssform = SongSelectForm(None, MagicMock(), MagicMock())
|
||||
mocked_song_select_importer = MagicMock()
|
||||
ssform.song_select_importer = mocked_song_select_importer
|
||||
ssform.song = None
|
||||
|
||||
# WHEN: The import button is clicked, and the user clicks Yes
|
||||
with patch.object(ssform, 'done') as mocked_done:
|
||||
ssform.on_import_button_clicked()
|
||||
|
||||
# THEN: The on_back_button_clicked() method should have been called
|
||||
mocked_song_select_importer.save_song.assert_called_with(None)
|
||||
mocked_question.assert_called_with(ssform, 'Song Imported',
|
||||
'Your song has been imported, would you like to import more songs?',
|
||||
QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.Yes)
|
||||
mocked_done.assert_called_with(QtGui.QDialog.Accepted)
|
||||
|
||||
def on_back_button_clicked_test(self):
|
||||
"""
|
||||
Test that when the back button is clicked, the stacked widget is set back one page
|
||||
"""
|
||||
# GIVEN: A SongSelect form
|
||||
ssform = SongSelectForm(None, MagicMock(), MagicMock())
|
||||
|
||||
# WHEN: The back button is clicked
|
||||
with patch.object(ssform, 'stacked_widget') as mocked_stacked_widget, \
|
||||
patch.object(ssform, 'search_combobox') as mocked_search_combobox:
|
||||
ssform.on_back_button_clicked()
|
||||
|
||||
# THEN: The stacked widget should be set back one page
|
||||
mocked_stacked_widget.setCurrentIndex.assert_called_with(1)
|
||||
mocked_search_combobox.setFocus.assert_called_with()
|
||||
|
||||
@patch('openlp.plugins.songs.forms.songselectform.QtGui.QMessageBox.information')
|
||||
def on_search_show_info_test(self, mocked_information):
|
||||
"""
|
||||
Test that when the search_show_info signal is emitted, the on_search_show_info() method shows a dialog
|
||||
"""
|
||||
# GIVEN: A SongSelect form
|
||||
ssform = SongSelectForm(None, MagicMock(), MagicMock())
|
||||
expected_title = 'Test Title'
|
||||
expected_text = 'This is a test'
|
||||
|
||||
# WHEN: on_search_show_info is called
|
||||
ssform.on_search_show_info(expected_title, expected_text)
|
||||
|
||||
# THEN: An information dialog should be shown
|
||||
mocked_information.assert_called_with(ssform, expected_title, expected_text)
|
||||
|
||||
def update_login_progress_test(self):
|
||||
"""
|
||||
Test the _update_login_progress() method
|
||||
"""
|
||||
# GIVEN: A SongSelect form
|
||||
ssform = SongSelectForm(None, MagicMock(), MagicMock())
|
||||
|
||||
# WHEN: _update_login_progress() is called
|
||||
with patch.object(ssform, 'login_progress_bar') as mocked_login_progress_bar:
|
||||
mocked_login_progress_bar.value.return_value = 3
|
||||
ssform._update_login_progress()
|
||||
|
||||
# THEN: The login progress bar should be updated
|
||||
mocked_login_progress_bar.setValue.assert_called_with(4)
|
||||
|
||||
def update_song_progress_test(self):
|
||||
"""
|
||||
Test the _update_song_progress() method
|
||||
"""
|
||||
# GIVEN: A SongSelect form
|
||||
ssform = SongSelectForm(None, MagicMock(), MagicMock())
|
||||
|
||||
# WHEN: _update_song_progress() is called
|
||||
with patch.object(ssform, 'song_progress_bar') as mocked_song_progress_bar:
|
||||
mocked_song_progress_bar.value.return_value = 2
|
||||
ssform._update_song_progress()
|
||||
|
||||
# THEN: The song progress bar should be updated
|
||||
mocked_song_progress_bar.setValue.assert_called_with(3)
|
||||
|
||||
def on_search_results_widget_double_clicked_test(self):
|
||||
"""
|
||||
Test that a song is retrieved when a song in the results list is double-clicked
|
||||
"""
|
||||
# GIVEN: A SongSelect form
|
||||
ssform = SongSelectForm(None, MagicMock(), MagicMock())
|
||||
expected_song = {'title': 'Amazing Grace'}
|
||||
|
||||
# WHEN: A song result is double-clicked
|
||||
with patch.object(ssform, '_view_song') as mocked_view_song:
|
||||
ssform.on_search_results_widget_double_clicked(expected_song)
|
||||
|
||||
# THEN: The song is fetched and shown to the user
|
||||
mocked_view_song.assert_called_with(expected_song)
|
||||
|
||||
def on_view_button_clicked_test(self):
|
||||
"""
|
||||
Test that a song is retrieved when the view button is clicked
|
||||
"""
|
||||
# GIVEN: A SongSelect form
|
||||
ssform = SongSelectForm(None, MagicMock(), MagicMock())
|
||||
expected_song = {'title': 'Amazing Grace'}
|
||||
|
||||
# WHEN: A song result is double-clicked
|
||||
with patch.object(ssform, '_view_song') as mocked_view_song, \
|
||||
patch.object(ssform, 'search_results_widget') as mocked_search_results_widget:
|
||||
mocked_search_results_widget.currentItem.return_value = expected_song
|
||||
ssform.on_view_button_clicked()
|
||||
|
||||
# THEN: The song is fetched and shown to the user
|
||||
mocked_view_song.assert_called_with(expected_song)
|
||||
|
||||
def on_search_results_widget_selection_changed_test(self):
|
||||
"""
|
||||
Test that the view button is updated when the search results list is changed
|
||||
"""
|
||||
# GIVEN: A SongSelect form
|
||||
ssform = SongSelectForm(None, MagicMock(), MagicMock())
|
||||
|
||||
# WHEN: There is at least 1 item selected
|
||||
with patch.object(ssform, 'search_results_widget') as mocked_search_results_widget, \
|
||||
patch.object(ssform, 'view_button') as mocked_view_button:
|
||||
mocked_search_results_widget.selectedItems.return_value = [1]
|
||||
ssform.on_search_results_widget_selection_changed()
|
||||
|
||||
# THEN: The view button should be enabled
|
||||
mocked_view_button.setEnabled.assert_called_with(True)
|
||||
|
||||
|
||||
class TestSongSelectFileImport(TestCase, TestMixin):
|
||||
"""
|
||||
@ -481,53 +643,45 @@ class TestSongSelectFileImport(TestCase, TestMixin):
|
||||
self.authors = ['Author One', 'Author Two']
|
||||
self.topics = ['Adoration', 'Praise']
|
||||
|
||||
def tearDown(self):
|
||||
def songselect_import_bin_file_test(self):
|
||||
"""
|
||||
Test cleanups
|
||||
:return:
|
||||
"""
|
||||
pass
|
||||
|
||||
def songselect_import_usr_file_test(self):
|
||||
"""
|
||||
Verify import SongSelect USR file parses file properly
|
||||
Verify import SongSelect BIN file parses file properly
|
||||
:return:
|
||||
"""
|
||||
# GIVEN: Text file to import and mocks
|
||||
copyright = '2011 OpenLP Programmer One (Admin. by OpenLP One) | ' \
|
||||
copyright_bin = '2011 OpenLP Programmer One (Admin. by OpenLP One) | ' \
|
||||
'Openlp Programmer Two (Admin. by OpenLP Two)'
|
||||
verses = [
|
||||
verses_bin = [
|
||||
['v1', 'Line One Verse One\nLine Two Verse One\nLine Three Verse One\nLine Four Verse One', None],
|
||||
['v2', 'Line One Verse Two\nLine Two Verse Two\nLine Three Verse Two\nLine Four Verse Two', None]
|
||||
]
|
||||
song_import = CCLIFileImport(manager=None, filename=['{}.bin'.format(self.file_name)])
|
||||
|
||||
song_import = CCLIFileImport(manager=None, filename=['{}.bin'.format(self.file_name)], )
|
||||
with patch.object(song_import, 'import_wizard'), patch.object(song_import, 'finish'):
|
||||
|
||||
# WHEN: We call the song importer
|
||||
song_import.do_import()
|
||||
# THEN: Song values should be equal to test values in setUp
|
||||
self.assertEquals(song_import.title, self.title, 'Song title should match')
|
||||
self.assertEquals(song_import.ccli_number, self.ccli_number, 'CCLI Song Number should match')
|
||||
self.assertEquals(song_import.authors, self.authors, 'Author(s) should match')
|
||||
self.assertEquals(song_import.copyright, self.copyright_usr, 'Copyright should match')
|
||||
self.assertEquals(song_import.copyright, copyright_bin, 'Copyright should match')
|
||||
self.assertEquals(song_import.topics, self.topics, 'Theme(s) should match')
|
||||
self.assertEquals(song_import.verses, self.verses, 'Verses should match with test verses')
|
||||
self.assertEquals(song_import.verses, verses_bin, 'Verses should match with test verses')
|
||||
|
||||
def songselect_import_usr_file_test(self):
|
||||
def songselect_import_txt_file_test(self):
|
||||
"""
|
||||
Verify import SongSelect USR file parses file properly
|
||||
Verify import SongSelect TXT file parses file properly
|
||||
:return:
|
||||
"""
|
||||
# GIVEN: Text file to import and mocks
|
||||
copyright = '© 2011 OpenLP Programmer One (Admin. by OpenLP One)'
|
||||
verses = [
|
||||
copyright_txt = '© 2011 OpenLP Programmer One (Admin. by OpenLP One)'
|
||||
verses_txt = [
|
||||
['v1', 'Line One Verse One\r\nLine Two Verse One\r\nLine Three Verse One\r\nLine Four Verse One', None],
|
||||
['v2', 'Line One Verse Two\r\nLine Two Verse Two\r\nLine Three Verse Two\r\nLine Four Verse Two', None]
|
||||
]
|
||||
song_import = CCLIFileImport(manager=None, filename=['{}.txt'.format(self.file_name)], )
|
||||
with patch.object(song_import, 'import_wizard'), patch.object(song_import, 'finish'):
|
||||
song_import = CCLIFileImport(manager=None, filename=['{}.txt'.format(self.file_name)])
|
||||
|
||||
with patch.object(song_import, 'import_wizard'), patch.object(song_import, 'finish'):
|
||||
# WHEN: We call the song importer
|
||||
song_import.do_import()
|
||||
|
||||
@ -535,5 +689,87 @@ class TestSongSelectFileImport(TestCase, TestMixin):
|
||||
self.assertEquals(song_import.title, self.title, 'Song title should match')
|
||||
self.assertEquals(song_import.ccli_number, self.ccli_number, 'CCLI Song Number should match')
|
||||
self.assertEquals(song_import.authors, self.authors, 'Author(s) should match')
|
||||
self.assertEquals(song_import.copyright, copyright, 'Copyright should match')
|
||||
self.assertEquals(song_import.verses, verses, 'Verses should match with test verses')
|
||||
self.assertEquals(song_import.copyright, copyright_txt, 'Copyright should match')
|
||||
self.assertEquals(song_import.verses, verses_txt, 'Verses should match with test verses')
|
||||
|
||||
|
||||
class TestSearchWorker(TestCase, TestMixin):
|
||||
"""
|
||||
Test the SearchWorker class
|
||||
"""
|
||||
def constructor_test(self):
|
||||
"""
|
||||
Test the SearchWorker constructor
|
||||
"""
|
||||
# GIVEN: An importer mock object and some search text
|
||||
importer = MagicMock()
|
||||
search_text = 'Jesus'
|
||||
|
||||
# WHEN: The search worker is created
|
||||
worker = SearchWorker(importer, search_text)
|
||||
|
||||
# THEN: The correct values should be set
|
||||
self.assertIs(importer, worker.importer, 'The importer should be the right object')
|
||||
self.assertEqual(search_text, worker.search_text, 'The search text should be correct')
|
||||
|
||||
def start_test(self):
|
||||
"""
|
||||
Test the start() method of the SearchWorker class
|
||||
"""
|
||||
# GIVEN: An importer mock object, some search text and an initialised SearchWorker
|
||||
importer = MagicMock()
|
||||
importer.search.return_value = ['song1', 'song2']
|
||||
search_text = 'Jesus'
|
||||
worker = SearchWorker(importer, search_text)
|
||||
|
||||
# WHEN: The start() method is called
|
||||
with patch.object(worker, 'finished') as mocked_finished, patch.object(worker, 'quit') as mocked_quit:
|
||||
worker.start()
|
||||
|
||||
# THEN: The "finished" and "quit" signals should be emitted
|
||||
importer.search.assert_called_with(search_text, 1000, worker._found_song_callback)
|
||||
mocked_finished.emit.assert_called_with()
|
||||
mocked_quit.emit.assert_called_with()
|
||||
|
||||
@patch('openlp.plugins.songs.forms.songselectform.translate')
|
||||
def start_over_1000_songs_test(self, mocked_translate):
|
||||
"""
|
||||
Test the start() method of the SearchWorker class when it finds over 1000 songs
|
||||
"""
|
||||
# GIVEN: An importer mock object, some search text and an initialised SearchWorker
|
||||
mocked_translate.side_effect = lambda x, y: y
|
||||
importer = MagicMock()
|
||||
importer.search.return_value = ['song%s' % num for num in range(1050)]
|
||||
search_text = 'Jesus'
|
||||
worker = SearchWorker(importer, search_text)
|
||||
|
||||
# WHEN: The start() method is called
|
||||
with patch.object(worker, 'finished') as mocked_finished, patch.object(worker, 'quit') as mocked_quit, \
|
||||
patch.object(worker, 'show_info') as mocked_show_info:
|
||||
worker.start()
|
||||
|
||||
# THEN: The "finished" and "quit" signals should be emitted
|
||||
importer.search.assert_called_with(search_text, 1000, worker._found_song_callback)
|
||||
mocked_show_info.emit.assert_called_with('More than 1000 results', 'Your search has returned more than 1000 '
|
||||
'results, it has been stopped. Please '
|
||||
'refine your search to fetch better '
|
||||
'results.')
|
||||
mocked_finished.emit.assert_called_with()
|
||||
mocked_quit.emit.assert_called_with()
|
||||
|
||||
def found_song_callback_test(self):
|
||||
"""
|
||||
Test that when the _found_song_callback() function is called, the "found_song" signal is emitted
|
||||
"""
|
||||
# GIVEN: An importer mock object, some search text and an initialised SearchWorker
|
||||
importer = MagicMock()
|
||||
search_text = 'Jesus'
|
||||
song = {'title': 'Amazing Grace'}
|
||||
worker = SearchWorker(importer, search_text)
|
||||
|
||||
# WHEN: The start() method is called
|
||||
with patch.object(worker, 'found_song') as mocked_found_song:
|
||||
worker._found_song_callback(song)
|
||||
|
||||
# THEN: The "found_song" signal should have been emitted
|
||||
mocked_found_song.emit.assert_called_with(song)
|
||||
|
Loading…
Reference in New Issue
Block a user