mirror of https://gitlab.com/openlp/openlp.git
681 lines
27 KiB
Python
681 lines
27 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
##########################################################################
|
|
# OpenLP - Open Source Lyrics Projection #
|
|
# ---------------------------------------------------------------------- #
|
|
# Copyright (c) 2008-2024 OpenLP Developers #
|
|
# ---------------------------------------------------------------------- #
|
|
# This program is free software: you can redistribute it and/or modify #
|
|
# it under the terms of the GNU General Public License as published by #
|
|
# the Free Software Foundation, either version 3 of the License, or #
|
|
# (at your option) any later version. #
|
|
# #
|
|
# This program is distributed in the hope that it will be useful, #
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
|
# GNU General Public License for more details. #
|
|
# #
|
|
# You should have received a copy of the GNU General Public License #
|
|
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
|
|
##########################################################################
|
|
|
|
"""
|
|
This module contains tests for the CCLI SongSelect importer.
|
|
It needs re-writing at some point to load real HTML pages from disk and
|
|
then test the behaviour based on those. That way if and when CCLI change
|
|
their page layout, changing the tests would just be a case of
|
|
re-downloading the HTML pages and changing the code to use the new layout.
|
|
"""
|
|
from unittest.mock import MagicMock, patch, sentinel
|
|
|
|
import pytest
|
|
from PyQt5 import QtCore
|
|
|
|
from openlp.core.common.registry import Registry
|
|
from openlp.core.common.settings import Settings
|
|
from openlp.plugins.songs.forms.songselectform import SongSelectForm
|
|
from openlp.plugins.songs.lib import Song
|
|
from openlp.plugins.songs.lib.songselect import BASE_URL, LOGIN_PAGE, Pages, SongSelectImport
|
|
from tests.helpers.songfileimport import SongImportTestHelper
|
|
from tests.utils.constants import RESOURCE_PATH
|
|
|
|
|
|
TEST_PATH = RESOURCE_PATH / 'songs' / 'songselect'
|
|
|
|
|
|
@pytest.fixture
|
|
def importer(registry: Registry, settings: Settings) -> SongSelectImport:
|
|
"""An importer object"""
|
|
yield SongSelectImport(MagicMock(), MagicMock())
|
|
|
|
|
|
@pytest.fixture
|
|
def form(registry: Registry, settings: Settings) -> SongSelectForm:
|
|
"""A SongSelectForm object"""
|
|
# registry.get('application').setApplicationVersion('0.0')
|
|
# registry.get('application').processEvents = lambda: None
|
|
with patch('openlp.plugins.songs.forms.songselectdialog.QtWidgets.QGridLayout'), \
|
|
patch('openlp.plugins.songs.forms.songselectdialog.WebEngineView'), \
|
|
patch('openlp.plugins.songs.forms.songselectdialog.QtWidgets.QVBoxLayout'):
|
|
yield SongSelectForm(None, MagicMock(), MagicMock())
|
|
|
|
|
|
def test_constructor(registry: Registry, settings: Settings):
|
|
"""
|
|
Test that constructing a basic SongSelectImport object works correctly
|
|
"""
|
|
# GIVEN: The SongSelectImporter class and a mocked out build_opener
|
|
# WHEN: An object is instantiated
|
|
importer = SongSelectImport(sentinel.db_manager, sentinel.webview)
|
|
|
|
# THEN: The object should have the correct properties
|
|
assert importer.db_manager is sentinel.db_manager, 'The db_manager should be set'
|
|
assert importer.webview is sentinel.webview, 'The webview should be set'
|
|
|
|
|
|
def test_get_page_type_login(importer: SongSelectImport):
|
|
"""
|
|
Test get_page_type to spot the login page
|
|
"""
|
|
# GIVEN: A importer object, and a mocked url
|
|
url = QtCore.QUrl('https://profile.ccli.com/account/signin?appContext=SongSelect&'
|
|
'returnUrl=https%3a%2f%2fsongselect.ccli.com%2f')
|
|
page = MagicMock(url=MagicMock(return_value=url))
|
|
importer.webview = MagicMock(page=MagicMock(return_value=page))
|
|
|
|
# WHEN: The method is run
|
|
result = importer.get_page_type()
|
|
|
|
# THEN: The correct type should be returned
|
|
assert result == Pages.Login
|
|
|
|
|
|
def test_get_page_type_home(importer: SongSelectImport):
|
|
"""
|
|
Test get_page_type to spot the home page
|
|
"""
|
|
# GIVEN: A importer object, and a mocked url
|
|
url = QtCore.QUrl('https://songselect.ccli.com')
|
|
page = MagicMock(url=MagicMock(return_value=url))
|
|
importer.webview = MagicMock(page=MagicMock(return_value=page))
|
|
|
|
# WHEN: The method is run
|
|
result = importer.get_page_type()
|
|
|
|
# THEN: The correct type should be returned
|
|
assert result == Pages.Home
|
|
|
|
|
|
def test_get_page_type_search(importer: SongSelectImport):
|
|
"""
|
|
Test get_page_type to spot the search page
|
|
"""
|
|
# GIVEN: A importer object, and a mocked url
|
|
url = QtCore.QUrl('https://songselect.ccli.com/search/results?SearchText=test')
|
|
page = MagicMock(url=MagicMock(return_value=url))
|
|
importer.webview = MagicMock(page=MagicMock(return_value=page))
|
|
|
|
# WHEN: The method is run
|
|
result = importer.get_page_type()
|
|
|
|
# THEN: The correct type should be returned
|
|
assert result == Pages.Search
|
|
|
|
|
|
def test_get_page_type_song(importer: SongSelectImport):
|
|
"""
|
|
Test get_page_type to spot the login page
|
|
"""
|
|
# GIVEN: A importer object, and a mocked url
|
|
url = QtCore.QUrl('https://songselect.ccli.com/Songs/7115744/song_name/view_lyrics')
|
|
page = MagicMock(url=MagicMock(return_value=url))
|
|
importer.webview = MagicMock(page=MagicMock(return_value=page))
|
|
|
|
# WHEN: The method is run
|
|
result = importer.get_page_type()
|
|
|
|
# THEN: The correct type should be returned
|
|
assert result == Pages.Song
|
|
|
|
|
|
def test_get_page_type_other(importer: SongSelectImport):
|
|
"""
|
|
Test get_page_type to spot the login page
|
|
"""
|
|
# GIVEN: A importer object, and a mocked url
|
|
url = QtCore.QUrl('https://openlp.org')
|
|
page = MagicMock(url=MagicMock(return_value=url))
|
|
importer.webview = MagicMock(page=MagicMock(return_value=page))
|
|
|
|
# WHEN: The method is run
|
|
result = importer.get_page_type()
|
|
|
|
# THEN: The correct type should be returned
|
|
assert result == Pages.Other
|
|
|
|
|
|
@patch('openlp.plugins.songs.lib.songselect.wait_for')
|
|
def test_run_javascript(mocked_wait_for: MagicMock, importer: SongSelectImport):
|
|
"""
|
|
Test run javascript calls the page object
|
|
"""
|
|
# GIVEN: A importer object and mocked run js fn
|
|
def runJs(script, handle_result):
|
|
handle_result('processed_{}'.format(script))
|
|
importer.webview = MagicMock()
|
|
page = MagicMock()
|
|
page.runJavaScript = runJs
|
|
importer.webview.page.return_value = page
|
|
|
|
# WHEN: The set login field method is called
|
|
result = importer._run_javascript('2 + 2')
|
|
|
|
# THEN: The javascript should have been called on the page object
|
|
assert result == 'processed_2 + 2'
|
|
|
|
|
|
def test_reset_webview(importer: SongSelectImport):
|
|
"""
|
|
Check that the setUrl method is called when the reset webview method is called
|
|
"""
|
|
# GIVEN: A importer object and mock webview
|
|
importer.webview = MagicMock()
|
|
|
|
# WHEN: The reset_webview method is called
|
|
importer.reset_webview()
|
|
|
|
# THEN: The setUrl function should have been called
|
|
importer.webview.setUrl.assert_called_with(QtCore.QUrl(LOGIN_PAGE))
|
|
|
|
|
|
@patch('openlp.plugins.songs.lib.songselect.SongSelectImport.set_page')
|
|
def test_set_home_page(mocked_set_page: MagicMock, importer: SongSelectImport):
|
|
"""
|
|
Test that when the home method is called, it attempts to go to the home page
|
|
"""
|
|
# GIVEN: A importer object
|
|
# WHEN: The home method is called
|
|
importer.set_home_page()
|
|
|
|
# THEN: set_page is called once with the base url
|
|
mocked_set_page.assert_called_with(BASE_URL)
|
|
|
|
|
|
@patch('openlp.plugins.songs.lib.songselect.SongSelectImport._run_javascript')
|
|
def test_set_page(mocked_run_js: MagicMock, importer: SongSelectImport):
|
|
"""
|
|
Test set page runs the correct script
|
|
"""
|
|
# GIVEN: A importer object
|
|
# WHEN: The set login field method is called
|
|
importer.set_page('my_new_page')
|
|
|
|
# THEN: The javascript called should contain the correct values
|
|
mocked_run_js.assert_called_with('document.location = "my_new_page"')
|
|
|
|
|
|
@patch('openlp.plugins.songs.lib.songselect.SongSelectImport._run_javascript')
|
|
def test_set_login_fields(mocked_run_js: MagicMock, importer: SongSelectImport):
|
|
"""
|
|
Test correct js is sent to set login fields
|
|
"""
|
|
# GIVEN: A importer object
|
|
# WHEN: The set login field method is called
|
|
importer.set_login_fields('my_username', 'my_password')
|
|
|
|
# THEN: The javascript called should contain the correct values
|
|
mocked_run_js.assert_called_with(('document.getElementById("EmailAddress").value = "my_username";'
|
|
'document.getElementById("Password").value = "my_password";'
|
|
))
|
|
|
|
|
|
@patch('openlp.plugins.songs.lib.songselect.SongSelectImport._run_javascript')
|
|
@patch('openlp.plugins.songs.lib.songselect.wait_for')
|
|
def test_get_page(mocked_wait_for: MagicMock, mocked_run_js: MagicMock, importer: SongSelectImport):
|
|
"""
|
|
Test get page sends js requests
|
|
"""
|
|
# GIVEN: A importer object
|
|
mocked_run_js.return_value = True
|
|
|
|
# WHEN: The get page method is called
|
|
importer.get_page("https://example.com")
|
|
|
|
# THEN: The javascript should be run
|
|
assert mocked_run_js.call_count == 2, 'Should be called once for request and once for fetch'
|
|
mocked_wait_for.assert_called_once()
|
|
|
|
|
|
def test_get_song_number_from_url(importer: SongSelectImport):
|
|
"""
|
|
Test the ccli number can be correctly obtained from a url
|
|
"""
|
|
# GIVEN: A importer object
|
|
# WHEN: The function is called with a valid url
|
|
result = importer.get_song_number_from_url('https://songselect.ccli.com/songs/4755360/amazing-grace')
|
|
|
|
# THEN: The ccli number is returned
|
|
assert result == '4755360', 'Should have found the ccli number from the url'
|
|
|
|
|
|
def test_get_song_number_from_url_nonumber(importer: SongSelectImport):
|
|
"""
|
|
Test the ccli number function returns None when no number is found
|
|
"""
|
|
# GIVEN: A importer object
|
|
# WHEN: The function is called with a valid url
|
|
result = importer.get_song_number_from_url('https://songselect.ccli.com/search/results?SearchText=song+4755360')
|
|
|
|
# THEN: The returned value should be None
|
|
assert result is None
|
|
|
|
|
|
@patch('openlp.plugins.songs.lib.songselect.clean_song')
|
|
@patch('openlp.plugins.songs.lib.songselect.Topic')
|
|
@patch('openlp.plugins.songs.lib.songselect.Author')
|
|
def test_save_song_new_author(MockedAuthor: MagicMock, MockedTopic: MagicMock, mocked_clean_song: MagicMock,
|
|
importer: SongSelectImport):
|
|
"""
|
|
Test that saving a song with a new author performs the correct actions
|
|
"""
|
|
# GIVEN: A song to save, and some mocked out objects
|
|
song_dict = {
|
|
'title': 'Arky Arky',
|
|
'authors': ['Public Domain'],
|
|
'verses': [
|
|
{'label': 'Verse 1', 'lyrics': 'The Lord told Noah: there\'s gonna be a floody, floody'},
|
|
{'label': 'Chorus 1', 'lyrics': 'So, rise and shine, and give God the glory, glory'},
|
|
{'label': 'Verse 2', 'lyrics': 'The Lord told Noah to build him an arky, arky'}
|
|
],
|
|
'copyright': 'Public Domain',
|
|
'ccli_number': '123456'
|
|
}
|
|
MockedAuthor.display_name.__eq__.return_value = False
|
|
MockedTopic.name.__eq__.return_value = False
|
|
importer.db_manager.get_object_filtered.return_value = None
|
|
|
|
# WHEN: The song is saved to the database
|
|
result = importer.save_song(song_dict)
|
|
|
|
# THEN: The return value should be a Song class and the mocked_db_manager should have been called
|
|
assert isinstance(result, Song), 'The returned value should be a Song object'
|
|
mocked_clean_song.assert_called_with(importer.db_manager, result)
|
|
assert 2 == importer.db_manager.save_object.call_count, 'The save_object() method should have been called twice'
|
|
importer.db_manager.get_object_filtered.assert_called_with(MockedAuthor, False)
|
|
MockedAuthor.assert_called_with(first_name='Public', last_name='Domain', display_name='Public Domain')
|
|
assert 1 == len(result.authors_songs), 'There should only be one author'
|
|
|
|
|
|
@patch('openlp.plugins.songs.lib.songselect.clean_song')
|
|
@patch('openlp.plugins.songs.lib.songselect.Author')
|
|
def test_save_song_existing_author(MockedAuthor: MagicMock, mocked_clean_song: MagicMock, importer: SongSelectImport):
|
|
"""
|
|
Test that saving a song with an existing author performs the correct actions
|
|
"""
|
|
# GIVEN: A song to save, and some mocked out objects
|
|
song_dict = {
|
|
'title': 'Arky Arky',
|
|
'authors': ['Public Domain'],
|
|
'verses': [
|
|
{'label': 'Verse 1', 'lyrics': 'The Lord told Noah: there\'s gonna be a floody, floody'},
|
|
{'label': 'Chorus 1', 'lyrics': 'So, rise and shine, and give God the glory, glory'},
|
|
{'label': 'Verse 2', 'lyrics': 'The Lord told Noah to build him an arky, arky'}
|
|
],
|
|
'copyright': 'Public Domain',
|
|
'ccli_number': '123456'
|
|
}
|
|
MockedAuthor.display_name.__eq__.return_value = False
|
|
importer.db_manager.get_object_filtered.return_value = MagicMock()
|
|
|
|
# WHEN: The song is saved to the database
|
|
result = importer.save_song(song_dict)
|
|
|
|
# THEN: The return value should be a Song class and the mocked_db_manager should have been called
|
|
assert isinstance(result, Song), 'The returned value should be a Song object'
|
|
mocked_clean_song.assert_called_with(importer.db_manager, result)
|
|
assert 2 == importer.db_manager.save_object.call_count, 'The save_object() method should have been called twice'
|
|
importer.db_manager.get_object_filtered.assert_called_with(MockedAuthor, False)
|
|
assert 0 == MockedAuthor.call_count, 'A new author should not have been instantiated'
|
|
assert 1 == len(result.authors_songs), 'There should only be one author'
|
|
|
|
|
|
@patch('openlp.plugins.songs.lib.songselect.clean_song')
|
|
@patch('openlp.plugins.songs.lib.songselect.Author')
|
|
def test_save_song_unknown_author(MockedAuthor: MagicMock, mocked_clean_song: MagicMock, importer: SongSelectImport):
|
|
"""
|
|
Test that saving a song with an author name of only one word performs the correct actions
|
|
"""
|
|
# GIVEN: A song to save, and some mocked out objects
|
|
song_dict = {
|
|
'title': 'Arky Arky',
|
|
'authors': ['Unknown'],
|
|
'verses': [
|
|
{'label': 'Verse 1', 'lyrics': 'The Lord told Noah: there\'s gonna be a floody, floody'},
|
|
{'label': 'Chorus 1', 'lyrics': 'So, rise and shine, and give God the glory, glory'},
|
|
{'label': 'Verse 2', 'lyrics': 'The Lord told Noah to build him an arky, arky'}
|
|
],
|
|
'copyright': 'Public Domain',
|
|
'ccli_number': '123456'
|
|
}
|
|
MockedAuthor.display_name.__eq__.return_value = False
|
|
importer.db_manager.get_object_filtered.return_value = None
|
|
|
|
# WHEN: The song is saved to the database
|
|
result = importer.save_song(song_dict)
|
|
|
|
# THEN: The return value should be a Song class and the mocked_db_manager should have been called
|
|
assert isinstance(result, Song), 'The returned value should be a Song object'
|
|
mocked_clean_song.assert_called_with(importer.db_manager, result)
|
|
assert 2 == importer.db_manager.save_object.call_count, 'The save_object() method should have been called twice'
|
|
importer.db_manager.get_object_filtered.assert_called_with(MockedAuthor, False)
|
|
MockedAuthor.assert_called_with(first_name='Unknown', last_name='', display_name='Unknown')
|
|
assert 1 == len(result.authors_songs), 'There should only be one author'
|
|
|
|
|
|
@patch('openlp.plugins.songs.lib.songselect.clean_song')
|
|
@patch('openlp.plugins.songs.lib.songselect.Topic')
|
|
@patch('openlp.plugins.songs.lib.songselect.Author')
|
|
def test_save_song_topics(MockedAuthor: MagicMock, MockedTopic: MagicMock, mocked_clean_song: MagicMock,
|
|
importer: SongSelectImport):
|
|
"""
|
|
Test that saving a song with topics performs the correct actions
|
|
Also check that a verse with no number is retitled to 1
|
|
"""
|
|
# GIVEN: A song to save, and some mocked out objects
|
|
song_dict = {
|
|
'title': 'Arky Arky',
|
|
'authors': ['Public Domain'],
|
|
'verses': [
|
|
{'label': 'Verse', 'lyrics': 'The Lord told Noah: there\'s gonna be a floody, floody'},
|
|
{'label': 'Chorus 1', 'lyrics': 'So, rise and shine, and give God the glory, glory'},
|
|
{'label': 'Verse 2', 'lyrics': 'The Lord told Noah to build him an arky, arky'}
|
|
],
|
|
'copyright': 'Public Domain',
|
|
'ccli_number': '123456',
|
|
'topics': ['Old Testement', 'Flood']
|
|
}
|
|
|
|
def save_object(b):
|
|
b.topics = []
|
|
|
|
MockedAuthor.display_name.__eq__.return_value = False
|
|
MockedTopic.name.__eq__.return_value = False
|
|
importer.db_manager.get_object_filtered.return_value = None
|
|
importer.db_manager.save_object = save_object
|
|
|
|
# WHEN: The song is saved to the database
|
|
result = importer.save_song(song_dict)
|
|
|
|
# THEN: The return value should be a Song class and the topics should have been added
|
|
assert isinstance(result, Song), 'The returned value should be a Song object'
|
|
mocked_clean_song.assert_called_with(importer.db_manager, result)
|
|
assert MockedTopic.call_count == 2, 'Should have created 2 new topics'
|
|
MockedTopic.assert_called_with(name='Flood')
|
|
assert 1 == len(result.authors_songs), 'There should only be one author'
|
|
|
|
|
|
def test_create_form(form: SongSelectForm):
|
|
"""
|
|
Test that we can create the SongSelect form
|
|
"""
|
|
# GIVEN: The SongSelectForm class and a mocked db manager
|
|
# WHEN: We create an instance
|
|
# THEN: The correct properties should have been assigned
|
|
assert isinstance(form.plugin, MagicMock), 'The correct plugin should have been assigned'
|
|
assert isinstance(form.db_manager, MagicMock), 'The correct db_manager should have been assigned'
|
|
|
|
|
|
@patch('openlp.plugins.songs.lib.songselect.SongSelectImport')
|
|
def test_initialise(mocked_ss_import: MagicMock, form: SongSelectForm):
|
|
"""
|
|
Test the initialise method
|
|
"""
|
|
# GIVEN: The SongSelectForm
|
|
# WHEN: The initialise method is run
|
|
form.initialise()
|
|
|
|
# THEN: The import object should exist, song var should be None, and the page hooked up
|
|
assert form.song is None
|
|
assert isinstance(form.song_select_importer, SongSelectImport), 'SongSelectImport object should be created'
|
|
assert form.webview.page.call_count == 5, 'Page should be called 5 times, once for each load handler and ' \
|
|
'one from setting user agent, one for user agent and one for JS inject'
|
|
|
|
|
|
@patch('openlp.plugins.songs.forms.songselectform.QtWidgets.QDialog.exec')
|
|
def test_exec(mocked_exec: MagicMock, form: SongSelectForm):
|
|
"""
|
|
Test the exec method
|
|
"""
|
|
# GIVEN: The SongSelectForm
|
|
form.song_select_importer = MagicMock()
|
|
form.stacked_widget = MagicMock()
|
|
|
|
# WHEN: The initialise method is run
|
|
form.exec()
|
|
|
|
# THEN: Should have reset webview, set stack to 0 and pass on the event
|
|
form.song_select_importer.reset_webview.assert_called_once()
|
|
form.stacked_widget.setCurrentIndex.assert_called_with(0)
|
|
mocked_exec.assert_called_once()
|
|
|
|
|
|
@patch('openlp.plugins.songs.forms.songselectform.QtWidgets.QDialog.done')
|
|
@patch('openlp.plugins.songs.forms.songselectform.QtWidgets.QProgressDialog')
|
|
def test_done(mocked_prog_dialog: MagicMock, mocked_done: MagicMock, form: SongSelectForm):
|
|
"""
|
|
Test the done method closes th dialog
|
|
"""
|
|
# GIVEN: The SongSelectForm
|
|
form.song_select_importer = MagicMock()
|
|
|
|
# WHEN: The initialise method is run
|
|
form.done('result')
|
|
|
|
# THEN: Should have passed on the event
|
|
mocked_done.assert_called_once()
|
|
|
|
|
|
def test_page_load_started(form: SongSelectForm):
|
|
"""
|
|
Test the page_load_started method
|
|
"""
|
|
# GIVEN: The SongSelectForm
|
|
form.back_button = MagicMock()
|
|
form.url_bar = MagicMock()
|
|
form.message_area = MagicMock()
|
|
|
|
# WHEN: The method is run
|
|
form.page_load_started()
|
|
|
|
# THEN: The UI should be set up accordingly
|
|
form.back_button.setEnabled.assert_called_with(False)
|
|
form.message_area.setText.assert_called_with('Import songs by clicking the "Download" in the Lyrics tab '
|
|
'or "Download ChordPro" in the Chords tabs.')
|
|
|
|
|
|
def test_page_loaded_login(form: SongSelectForm):
|
|
"""
|
|
Test the page_loaded method for a "Login" page
|
|
"""
|
|
# GIVEN: The SongSelectForm and mocked login page
|
|
form.song_select_importer = MagicMock()
|
|
form.song_select_importer.get_page_type.return_value = Pages.Login
|
|
form.signin_page_loaded = MagicMock()
|
|
form.url_bar = MagicMock()
|
|
|
|
# WHEN: The method is run
|
|
form.page_loaded(True)
|
|
|
|
# THEN: The signin page method should be called
|
|
form.signin_page_loaded.assert_called_once()
|
|
|
|
|
|
def test_page_loaded_other(form: SongSelectForm):
|
|
"""
|
|
Test the page_loaded method for an "Other" page
|
|
"""
|
|
# GIVEN: The SongSelectForm and mocked other page
|
|
form.song_select_importer = MagicMock()
|
|
form.song_select_importer.get_page_type.return_value = Pages.Other
|
|
form.song_progress_bar = MagicMock()
|
|
form.back_button = MagicMock()
|
|
form.url_bar = MagicMock()
|
|
|
|
# WHEN: The method is run
|
|
form.page_loaded(True)
|
|
|
|
# THEN: Back button should be available
|
|
form.back_button.setEnabled.assert_called_with(True)
|
|
|
|
|
|
def test_signin_page_loaded(form: SongSelectForm):
|
|
"""
|
|
Test that the signin_page_loaded method calls the appropriate method
|
|
"""
|
|
# GIVEN: The SongSelectForm and mocked settings
|
|
form.song_select_importer = MagicMock()
|
|
form.settings.value = MagicMock(side_effect=['user', 'pass'])
|
|
|
|
# WHEN: The method is run
|
|
form.signin_page_loaded()
|
|
|
|
# THEN: Correct values should have been sent from the settings
|
|
form.song_select_importer.set_login_fields.assert_called_with('user', 'pass')
|
|
|
|
|
|
@patch('openlp.plugins.songs.forms.songselectdialog.QtWidgets.QListWidgetItem')
|
|
def test_view_song(mock_qtlist: MagicMock, form: SongSelectForm):
|
|
"""
|
|
Test that the _view_song method does the important stuff
|
|
"""
|
|
# GIVEN: The SongSelectForm, mocks and a song
|
|
form.stacked_widget = MagicMock()
|
|
form.title_edit = MagicMock()
|
|
form.copyright_edit = MagicMock()
|
|
form.ccli_edit = MagicMock()
|
|
form.lyrics_table_widget = MagicMock()
|
|
form.author_list_widget = MagicMock()
|
|
form.song = {
|
|
'title': 'Song Title',
|
|
'copyright': 'copy thing',
|
|
'ccli_number': '1234',
|
|
'authors': ['Bob', 'Jo'],
|
|
'verses': [{'lyrics': 'hello', 'label': 'Verse 1'}]
|
|
}
|
|
|
|
# WHEN: The method is run
|
|
form._view_song()
|
|
|
|
# THEN: Page should have changed in the stacked widget and ui should have been updated
|
|
form.stacked_widget.setCurrentIndex.assert_called_with(1)
|
|
form.title_edit.setText.assert_called_with('Song Title')
|
|
form.copyright_edit.setText.assert_called_with('copy thing')
|
|
form.ccli_edit.setText.assert_called_with('1234')
|
|
assert form.lyrics_table_widget.setItem.call_count > 0
|
|
assert form.author_list_widget.addItem.call_count > 0
|
|
|
|
|
|
@patch('openlp.plugins.songs.forms.songselectform.QtWidgets.QMessageBox.critical')
|
|
def test_view_song_invalid(mock_message: MagicMock, form: SongSelectForm):
|
|
"""
|
|
Test that the _view_song doesn't mess up when the song doesn't exist
|
|
"""
|
|
# GIVEN: The SongSelectForm, mocks and a song
|
|
form.stacked_widget = MagicMock()
|
|
form.song = None
|
|
|
|
# WHEN: The method is run
|
|
form._view_song()
|
|
|
|
# THEN: Page should not have changed and a warning should show
|
|
assert form.stacked_widget.setCurrentIndex.call_count == 0
|
|
mock_message.assert_called_once()
|
|
|
|
|
|
def test_on_url_bar_return_pressed(form: SongSelectForm):
|
|
"""
|
|
Test that the on_url_bar_return_pressed method changes the page
|
|
"""
|
|
# GIVEN: The SongSelectForm, mocks and a song
|
|
form.url_bar = MagicMock()
|
|
form.url_bar.text.return_value = "test"
|
|
form.song_select_importer = MagicMock()
|
|
|
|
# WHEN: The method is run
|
|
form.on_url_bar_return_pressed()
|
|
|
|
# THEN: Page should not have changed and a warning should show
|
|
form.song_select_importer.set_page.assert_called_with("test")
|
|
|
|
|
|
def test_on_back_button_clicked_preview(form: SongSelectForm):
|
|
"""
|
|
Test that when the back button is clicked on preview screen, the stacked widget is set back one page
|
|
"""
|
|
# GIVEN: A SongSelect form, stacked widget on page 1
|
|
ssimporter = MagicMock()
|
|
form.song_select_importer = MagicMock()
|
|
form.song_select_importer.set_home_page = ssimporter
|
|
with patch.object(form, 'stacked_widget') as mocked_stacked_widget:
|
|
mocked_stacked_widget.currentIndex.return_value = 1
|
|
|
|
# WHEN: The preview back button is clicked
|
|
form.on_back_button_clicked()
|
|
|
|
# THEN: The stacked widget should be set back one page and webpage is NOT put back to the home page
|
|
mocked_stacked_widget.setCurrentIndex.assert_called_with(0)
|
|
ssimporter.assert_not_called()
|
|
|
|
|
|
def test_on_back_button_clicked_force(form: SongSelectForm):
|
|
"""
|
|
Test that when the back button method is triggered with the force param set,
|
|
the page should be changed
|
|
"""
|
|
# GIVEN: A SongSelect form, stacked widget on page 1
|
|
ssimporter = MagicMock()
|
|
form.song_select_importer = MagicMock()
|
|
form.song_select_importer.set_home_page = ssimporter
|
|
with patch.object(form, 'stacked_widget') as mocked_stacked_widget:
|
|
mocked_stacked_widget.currentIndex.return_value = 1
|
|
|
|
# WHEN: The preview back button is clicked with force param
|
|
form.on_back_button_clicked(True)
|
|
|
|
# THEN: The stacked widget should be set back one page and webpage is NOT put back to the home page
|
|
mocked_stacked_widget.setCurrentIndex.assert_called_with(0)
|
|
ssimporter.assert_called_once()
|
|
|
|
|
|
def test_on_back_button_clicked(form: SongSelectForm):
|
|
"""
|
|
Test that when the back button is clicked, the stacked widget is set to page 0
|
|
and set to home page
|
|
"""
|
|
# GIVEN: A SongSelect form, stacked widget on page 0
|
|
ssimporter = MagicMock()
|
|
form.song_select_importer = MagicMock()
|
|
form.song_select_importer.set_home_page = ssimporter
|
|
with patch.object(form, 'stacked_widget') as mocked_stacked_widget:
|
|
mocked_stacked_widget.currentIndex.return_value = 0
|
|
|
|
# WHEN: The back button is clicked
|
|
form.on_back_button_clicked()
|
|
|
|
# THEN: The stacked widget should be set back one page
|
|
mocked_stacked_widget.setCurrentIndex.assert_called_with(0)
|
|
ssimporter.assert_called_with()
|
|
|
|
|
|
def test_songselect_file_import(registry: Registry, settings: Settings):
|
|
"""
|
|
Test that loading a SongSelect file works correctly on various files
|
|
"""
|
|
with SongImportTestHelper('CCLIFileImport', 'cclifile') as helper:
|
|
helper.file_import([TEST_PATH / 'TestSong.bin'],
|
|
helper.load_external_result_data(TEST_PATH / 'TestSong-bin.json'))
|
|
helper.file_import([TEST_PATH / 'TestSong.txt'],
|
|
helper.load_external_result_data(TEST_PATH / 'TestSong-txt.json'))
|
|
helper.file_import([TEST_PATH / 'TestSong2023.txt'],
|
|
helper.load_external_result_data(TEST_PATH / 'TestSong2023-txt.json'))
|