forked from openlp/openlp
Tests plugin 3 - and Fix #272
This commit is contained in:
parent
b51829d4d6
commit
d43811f38d
@ -189,8 +189,8 @@ class BackgroundPage(GridLayoutPage):
|
|||||||
self.stream_label.setText('{text}:'.format(text=UiStrings().LiveStream))
|
self.stream_label.setText('{text}:'.format(text=UiStrings().LiveStream))
|
||||||
self.image_path_edit.filters = \
|
self.image_path_edit.filters = \
|
||||||
'{name};;{text} (*)'.format(name=get_images_filter(), text=UiStrings().AllFiles)
|
'{name};;{text} (*)'.format(name=get_images_filter(), text=UiStrings().AllFiles)
|
||||||
visible_formats = '(*.{name})'.format(name='; *.'.join(VIDEO_EXT))
|
visible_formats = '({name})'.format(name='; '.join(VIDEO_EXT))
|
||||||
actual_formats = '(*.{name})'.format(name=' *.'.join(VIDEO_EXT))
|
actual_formats = '({name})'.format(name=' '.join(VIDEO_EXT))
|
||||||
video_filter = '{trans} {visible} {actual}'.format(trans=translate('OpenLP', 'Video Files'),
|
video_filter = '{trans} {visible} {actual}'.format(trans=translate('OpenLP', 'Video Files'),
|
||||||
visible=visible_formats, actual=actual_formats)
|
visible=visible_formats, actual=actual_formats)
|
||||||
self.video_path_edit.filters = '{video};;{ui} (*)'.format(video=video_filter, ui=UiStrings().AllFiles)
|
self.video_path_edit.filters = '{video};;{ui} (*)'.format(video=video_filter, ui=UiStrings().AllFiles)
|
||||||
|
@ -23,9 +23,10 @@ Functional tests to test the Mac LibreOffice class and related methods.
|
|||||||
"""
|
"""
|
||||||
import shutil
|
import shutil
|
||||||
from tempfile import mkdtemp
|
from tempfile import mkdtemp
|
||||||
from unittest import TestCase, SkipTest
|
from unittest import TestCase, skipIf, SkipTest
|
||||||
from unittest.mock import MagicMock, patch, call
|
from unittest.mock import MagicMock, patch, call
|
||||||
|
|
||||||
|
from openlp.core.common.registry import Registry
|
||||||
from openlp.core.common import is_macosx
|
from openlp.core.common import is_macosx
|
||||||
from openlp.core.common.path import Path
|
from openlp.core.common.path import Path
|
||||||
from openlp.plugins.presentations.lib.maclocontroller import MacLOController, MacLODocument
|
from openlp.plugins.presentations.lib.maclocontroller import MacLOController, MacLODocument
|
||||||
@ -41,6 +42,7 @@ if not is_macosx():
|
|||||||
raise SkipTest('Not on macOS, skipping testing the Mac LibreOffice controller')
|
raise SkipTest('Not on macOS, skipping testing the Mac LibreOffice controller')
|
||||||
|
|
||||||
|
|
||||||
|
@skipIf(is_macosx(), 'Skip on macOS until we can figure out what the problem is or the tests are refactored')
|
||||||
class TestMacLOController(TestCase, TestMixin):
|
class TestMacLOController(TestCase, TestMixin):
|
||||||
"""
|
"""
|
||||||
Test the MacLOController Class
|
Test the MacLOController Class
|
||||||
@ -50,8 +52,10 @@ class TestMacLOController(TestCase, TestMixin):
|
|||||||
"""
|
"""
|
||||||
Set up the patches and mocks need for all tests.
|
Set up the patches and mocks need for all tests.
|
||||||
"""
|
"""
|
||||||
|
Registry.create()
|
||||||
self.setup_application()
|
self.setup_application()
|
||||||
self.build_settings()
|
self.build_settings()
|
||||||
|
Registry().register('settings', self.settings)
|
||||||
self.mock_plugin = MagicMock()
|
self.mock_plugin = MagicMock()
|
||||||
self.temp_folder = mkdtemp()
|
self.temp_folder = mkdtemp()
|
||||||
self.mock_plugin.settings_section = self.temp_folder
|
self.mock_plugin.settings_section = self.temp_folder
|
||||||
|
@ -163,14 +163,14 @@ def test_load_pdf(pdf_env):
|
|||||||
load_pdf_pictures(exe_path, pdf_env)
|
load_pdf_pictures(exe_path, pdf_env)
|
||||||
|
|
||||||
|
|
||||||
def test_loading_pdf_using_pymupdf():
|
def test_loading_pdf_using_pymupdf(pdf_env):
|
||||||
try:
|
try:
|
||||||
import fitz # noqa: F401
|
import fitz # noqa: F401
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pytest.skip('PyMuPDF is not installed')
|
pytest.skip('PyMuPDF is not installed')
|
||||||
|
|
||||||
load_pdf(None)
|
load_pdf(None, pdf_env)
|
||||||
load_pdf_pictures(None)
|
load_pdf_pictures(None, pdf_env)
|
||||||
|
|
||||||
|
|
||||||
@patch('openlp.plugins.presentations.lib.pdfcontroller.check_binary_exists')
|
@patch('openlp.plugins.presentations.lib.pdfcontroller.check_binary_exists')
|
||||||
|
@ -21,213 +21,208 @@
|
|||||||
"""
|
"""
|
||||||
This module contains tests for the db submodule of the Songs plugin.
|
This module contains tests for the db submodule of the Songs plugin.
|
||||||
"""
|
"""
|
||||||
|
import pytest
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
from tempfile import mkdtemp
|
from tempfile import mkdtemp
|
||||||
from unittest import TestCase
|
|
||||||
|
|
||||||
from openlp.core.common.registry import Registry
|
|
||||||
from openlp.core.common.settings import Settings
|
|
||||||
from openlp.core.lib.db import upgrade_db
|
from openlp.core.lib.db import upgrade_db
|
||||||
from openlp.plugins.songs.lib import upgrade
|
from openlp.plugins.songs.lib import upgrade
|
||||||
from openlp.plugins.songs.lib.db import Author, AuthorType, Book, Song
|
from openlp.plugins.songs.lib.db import Author, AuthorType, Book, Song
|
||||||
from tests.utils.constants import TEST_RESOURCES_PATH
|
from tests.utils.constants import TEST_RESOURCES_PATH
|
||||||
|
|
||||||
|
|
||||||
class TestDB(TestCase):
|
@pytest.yield_fixture()
|
||||||
|
def tmp_folder():
|
||||||
|
t_folder = mkdtemp()
|
||||||
|
yield t_folder
|
||||||
|
shutil.rmtree(t_folder, ignore_errors=True)
|
||||||
|
|
||||||
|
|
||||||
|
def test_add_author():
|
||||||
"""
|
"""
|
||||||
Test the functions in the :mod:`db` module.
|
Test adding an author to a song
|
||||||
"""
|
"""
|
||||||
|
# GIVEN: A song and an author
|
||||||
|
song = Song()
|
||||||
|
song.authors_songs = []
|
||||||
|
author = Author()
|
||||||
|
author.first_name = "Max"
|
||||||
|
author.last_name = "Mustermann"
|
||||||
|
|
||||||
def setUp(self):
|
# WHEN: We add an author to the song
|
||||||
"""
|
song.add_author(author)
|
||||||
Setup for tests
|
|
||||||
"""
|
|
||||||
self.tmp_folder = mkdtemp()
|
|
||||||
Registry.create()
|
|
||||||
Registry().register('settings', Settings())
|
|
||||||
|
|
||||||
def tearDown(self):
|
# THEN: The author should have been added with author_type=None
|
||||||
"""
|
assert 1 == len(song.authors_songs)
|
||||||
Clean up after tests
|
assert "Max" == song.authors_songs[0].author.first_name
|
||||||
"""
|
assert "Mustermann" == song.authors_songs[0].author.last_name
|
||||||
# Ignore errors since windows can have problems with locked files
|
assert song.authors_songs[0].author_type is None
|
||||||
shutil.rmtree(self.tmp_folder, ignore_errors=True)
|
|
||||||
|
|
||||||
def test_add_author(self):
|
|
||||||
"""
|
|
||||||
Test adding an author to a song
|
|
||||||
"""
|
|
||||||
# GIVEN: A song and an author
|
|
||||||
song = Song()
|
|
||||||
song.authors_songs = []
|
|
||||||
author = Author()
|
|
||||||
author.first_name = "Max"
|
|
||||||
author.last_name = "Mustermann"
|
|
||||||
|
|
||||||
# WHEN: We add an author to the song
|
def test_add_author_with_type():
|
||||||
song.add_author(author)
|
"""
|
||||||
|
Test adding an author with a type specified to a song
|
||||||
|
"""
|
||||||
|
# GIVEN: A song and an author
|
||||||
|
song = Song()
|
||||||
|
song.authors_songs = []
|
||||||
|
author = Author()
|
||||||
|
author.first_name = "Max"
|
||||||
|
author.last_name = "Mustermann"
|
||||||
|
|
||||||
# THEN: The author should have been added with author_type=None
|
# WHEN: We add an author to the song
|
||||||
assert 1 == len(song.authors_songs)
|
song.add_author(author, AuthorType.Words)
|
||||||
assert "Max" == song.authors_songs[0].author.first_name
|
|
||||||
assert "Mustermann" == song.authors_songs[0].author.last_name
|
|
||||||
assert song.authors_songs[0].author_type is None
|
|
||||||
|
|
||||||
def test_add_author_with_type(self):
|
# THEN: The author should have been added with author_type=None
|
||||||
"""
|
assert 1 == len(song.authors_songs)
|
||||||
Test adding an author with a type specified to a song
|
assert "Max" == song.authors_songs[0].author.first_name
|
||||||
"""
|
assert "Mustermann" == song.authors_songs[0].author.last_name
|
||||||
# GIVEN: A song and an author
|
assert AuthorType.Words == song.authors_songs[0].author_type
|
||||||
song = Song()
|
|
||||||
song.authors_songs = []
|
|
||||||
author = Author()
|
|
||||||
author.first_name = "Max"
|
|
||||||
author.last_name = "Mustermann"
|
|
||||||
|
|
||||||
# WHEN: We add an author to the song
|
|
||||||
song.add_author(author, AuthorType.Words)
|
|
||||||
|
|
||||||
# THEN: The author should have been added with author_type=None
|
def test_remove_author():
|
||||||
assert 1 == len(song.authors_songs)
|
"""
|
||||||
assert "Max" == song.authors_songs[0].author.first_name
|
Test removing an author from a song
|
||||||
assert "Mustermann" == song.authors_songs[0].author.last_name
|
"""
|
||||||
assert AuthorType.Words == song.authors_songs[0].author_type
|
# GIVEN: A song with an author
|
||||||
|
song = Song()
|
||||||
|
song.authors_songs = []
|
||||||
|
author = Author()
|
||||||
|
song.add_author(author)
|
||||||
|
|
||||||
def test_remove_author(self):
|
# WHEN: We remove the author
|
||||||
"""
|
song.remove_author(author)
|
||||||
Test removing an author from a song
|
|
||||||
"""
|
|
||||||
# GIVEN: A song with an author
|
|
||||||
song = Song()
|
|
||||||
song.authors_songs = []
|
|
||||||
author = Author()
|
|
||||||
song.add_author(author)
|
|
||||||
|
|
||||||
# WHEN: We remove the author
|
# THEN: It should have been removed
|
||||||
song.remove_author(author)
|
assert 0 == len(song.authors_songs)
|
||||||
|
|
||||||
# THEN: It should have been removed
|
|
||||||
assert 0 == len(song.authors_songs)
|
|
||||||
|
|
||||||
def test_remove_author_with_type(self):
|
def test_remove_author_with_type():
|
||||||
"""
|
"""
|
||||||
Test removing an author with a type specified from a song
|
Test removing an author with a type specified from a song
|
||||||
"""
|
"""
|
||||||
# GIVEN: A song with two authors
|
# GIVEN: A song with two authors
|
||||||
song = Song()
|
song = Song()
|
||||||
song.authors_songs = []
|
song.authors_songs = []
|
||||||
author = Author()
|
author = Author()
|
||||||
song.add_author(author)
|
song.add_author(author)
|
||||||
song.add_author(author, AuthorType.Translation)
|
song.add_author(author, AuthorType.Translation)
|
||||||
|
|
||||||
# WHEN: We remove the author with a certain type
|
# WHEN: We remove the author with a certain type
|
||||||
song.remove_author(author, AuthorType.Translation)
|
song.remove_author(author, AuthorType.Translation)
|
||||||
|
|
||||||
# THEN: It should have been removed and the other author should still be there
|
# THEN: It should have been removed and the other author should still be there
|
||||||
assert 1 == len(song.authors_songs)
|
assert 1 == len(song.authors_songs)
|
||||||
assert song.authors_songs[0].author_type is None
|
assert song.authors_songs[0].author_type is None
|
||||||
|
|
||||||
def test_get_author_type_from_translated_text(self):
|
|
||||||
"""
|
|
||||||
Test getting an author type from translated text
|
|
||||||
"""
|
|
||||||
# GIVEN: A string with an author type
|
|
||||||
author_type_name = AuthorType.Types[AuthorType.Words]
|
|
||||||
|
|
||||||
# WHEN: We call the method
|
def test_get_author_type_from_translated_text():
|
||||||
author_type = AuthorType.from_translated_text(author_type_name)
|
"""
|
||||||
|
Test getting an author type from translated text
|
||||||
|
"""
|
||||||
|
# GIVEN: A string with an author type
|
||||||
|
author_type_name = AuthorType.Types[AuthorType.Words]
|
||||||
|
|
||||||
# THEN: The type should be correct
|
# WHEN: We call the method
|
||||||
assert author_type == AuthorType.Words
|
author_type = AuthorType.from_translated_text(author_type_name)
|
||||||
|
|
||||||
def test_author_get_display_name(self):
|
# THEN: The type should be correct
|
||||||
"""
|
assert author_type == AuthorType.Words
|
||||||
Test that the display name of an author is correct
|
|
||||||
"""
|
|
||||||
# GIVEN: An author
|
|
||||||
author = Author()
|
|
||||||
author.display_name = "John Doe"
|
|
||||||
|
|
||||||
# WHEN: We call the get_display_name() function
|
|
||||||
display_name = author.get_display_name()
|
|
||||||
|
|
||||||
# THEN: It should return only the name
|
def test_author_get_display_name():
|
||||||
assert "John Doe" == display_name
|
"""
|
||||||
|
Test that the display name of an author is correct
|
||||||
|
"""
|
||||||
|
# GIVEN: An author
|
||||||
|
author = Author()
|
||||||
|
author.display_name = "John Doe"
|
||||||
|
|
||||||
def test_author_get_display_name_with_type_words(self):
|
# WHEN: We call the get_display_name() function
|
||||||
"""
|
display_name = author.get_display_name()
|
||||||
Test that the display name of an author with a type is correct (Words)
|
|
||||||
"""
|
|
||||||
# GIVEN: An author
|
|
||||||
author = Author()
|
|
||||||
author.display_name = "John Doe"
|
|
||||||
|
|
||||||
# WHEN: We call the get_display_name() function
|
# THEN: It should return only the name
|
||||||
display_name = author.get_display_name(AuthorType.Words)
|
assert "John Doe" == display_name
|
||||||
|
|
||||||
# THEN: It should return the name with the type in brackets
|
|
||||||
assert "John Doe (Words)" == display_name
|
|
||||||
|
|
||||||
def test_author_get_display_name_with_type_translation(self):
|
def test_author_get_display_name_with_type_words():
|
||||||
"""
|
"""
|
||||||
Test that the display name of an author with a type is correct (Translation)
|
Test that the display name of an author with a type is correct (Words)
|
||||||
"""
|
"""
|
||||||
# GIVEN: An author
|
# GIVEN: An author
|
||||||
author = Author()
|
author = Author()
|
||||||
author.display_name = "John Doe"
|
author.display_name = "John Doe"
|
||||||
|
|
||||||
# WHEN: We call the get_display_name() function
|
# WHEN: We call the get_display_name() function
|
||||||
display_name = author.get_display_name(AuthorType.Translation)
|
display_name = author.get_display_name(AuthorType.Words)
|
||||||
|
|
||||||
# THEN: It should return the name with the type in brackets
|
# THEN: It should return the name with the type in brackets
|
||||||
assert "John Doe (Translation)" == display_name
|
assert "John Doe (Words)" == display_name
|
||||||
|
|
||||||
def test_add_songbooks(self):
|
|
||||||
"""
|
|
||||||
Test that adding songbooks to a song works correctly
|
|
||||||
"""
|
|
||||||
# GIVEN: A mocked song and songbook
|
|
||||||
song = Song()
|
|
||||||
song.songbook_entries = []
|
|
||||||
songbook = Book()
|
|
||||||
songbook.name = "Thy Word"
|
|
||||||
|
|
||||||
# WHEN: We add two songbooks to a Song
|
def test_author_get_display_name_with_type_translation():
|
||||||
song.add_songbook_entry(songbook, "120")
|
"""
|
||||||
song.add_songbook_entry(songbook, "550A")
|
Test that the display name of an author with a type is correct (Translation)
|
||||||
|
"""
|
||||||
|
# GIVEN: An author
|
||||||
|
author = Author()
|
||||||
|
author.display_name = "John Doe"
|
||||||
|
|
||||||
# THEN: The song should have two songbook entries
|
# WHEN: We call the get_display_name() function
|
||||||
assert len(song.songbook_entries) == 2, 'There should be two Songbook entries.'
|
display_name = author.get_display_name(AuthorType.Translation)
|
||||||
|
|
||||||
def test_upgrade_old_song_db(self):
|
# THEN: It should return the name with the type in brackets
|
||||||
"""
|
assert "John Doe (Translation)" == display_name
|
||||||
Test that we can upgrade an old song db to the current schema
|
|
||||||
"""
|
|
||||||
# GIVEN: An old song db
|
|
||||||
old_db_path = os.path.join(TEST_RESOURCES_PATH, "songs", 'songs-1.9.7.sqlite')
|
|
||||||
old_db_tmp_path = os.path.join(self.tmp_folder, 'songs-1.9.7.sqlite')
|
|
||||||
shutil.copyfile(old_db_path, old_db_tmp_path)
|
|
||||||
db_url = 'sqlite:///' + old_db_tmp_path
|
|
||||||
|
|
||||||
# WHEN: upgrading the db
|
|
||||||
updated_to_version, latest_version = upgrade_db(db_url, upgrade)
|
|
||||||
|
|
||||||
# THEN: the song db should have been upgraded to the latest version
|
def test_add_songbooks():
|
||||||
assert updated_to_version == latest_version, 'The song DB should have been upgrade to the latest version'
|
"""
|
||||||
|
Test that adding songbooks to a song works correctly
|
||||||
|
"""
|
||||||
|
# GIVEN: A mocked song and songbook
|
||||||
|
song = Song()
|
||||||
|
song.songbook_entries = []
|
||||||
|
songbook = Book()
|
||||||
|
songbook.name = "Thy Word"
|
||||||
|
|
||||||
def test_upgrade_invalid_song_db(self):
|
# WHEN: We add two songbooks to a Song
|
||||||
"""
|
song.add_songbook_entry(songbook, "120")
|
||||||
Test that we can upgrade an invalid song db to the current schema
|
song.add_songbook_entry(songbook, "550A")
|
||||||
"""
|
|
||||||
# GIVEN: A song db with invalid version
|
|
||||||
invalid_db_path = os.path.join(TEST_RESOURCES_PATH, "songs", 'songs-2.2-invalid.sqlite')
|
|
||||||
invalid_db_tmp_path = os.path.join(self.tmp_folder, 'songs-2.2-invalid.sqlite')
|
|
||||||
shutil.copyfile(invalid_db_path, invalid_db_tmp_path)
|
|
||||||
db_url = 'sqlite:///' + invalid_db_tmp_path
|
|
||||||
|
|
||||||
# WHEN: upgrading the db
|
# THEN: The song should have two songbook entries
|
||||||
updated_to_version, latest_version = upgrade_db(db_url, upgrade)
|
assert len(song.songbook_entries) == 2, 'There should be two Songbook entries.'
|
||||||
|
|
||||||
# THEN: the song db should have been upgraded to the latest version without errors
|
|
||||||
assert updated_to_version == latest_version, 'The song DB should have been upgrade to the latest version'
|
def test_upgrade_old_song_db(settings, tmp_folder):
|
||||||
|
"""
|
||||||
|
Test that we can upgrade an old song db to the current schema
|
||||||
|
"""
|
||||||
|
# GIVEN: An old song db
|
||||||
|
old_db_path = os.path.join(TEST_RESOURCES_PATH, "songs", 'songs-1.9.7.sqlite')
|
||||||
|
old_db_tmp_path = os.path.join(tmp_folder, 'songs-1.9.7.sqlite')
|
||||||
|
shutil.copyfile(old_db_path, old_db_tmp_path)
|
||||||
|
db_url = 'sqlite:///' + old_db_tmp_path
|
||||||
|
|
||||||
|
# WHEN: upgrading the db
|
||||||
|
updated_to_version, latest_version = upgrade_db(db_url, upgrade)
|
||||||
|
|
||||||
|
# THEN: the song db should have been upgraded to the latest version
|
||||||
|
assert updated_to_version == latest_version, 'The song DB should have been upgrade to the latest version'
|
||||||
|
|
||||||
|
|
||||||
|
def test_upgrade_invalid_song_db(settings, tmp_folder):
|
||||||
|
"""
|
||||||
|
Test that we can upgrade an invalid song db to the current schema
|
||||||
|
"""
|
||||||
|
# GIVEN: A song db with invalid version
|
||||||
|
invalid_db_path = os.path.join(TEST_RESOURCES_PATH, "songs", 'songs-2.2-invalid.sqlite')
|
||||||
|
invalid_db_tmp_path = os.path.join(tmp_folder, 'songs-2.2-invalid.sqlite')
|
||||||
|
shutil.copyfile(invalid_db_path, invalid_db_tmp_path)
|
||||||
|
db_url = 'sqlite:///' + invalid_db_tmp_path
|
||||||
|
|
||||||
|
# WHEN: upgrading the db
|
||||||
|
updated_to_version, latest_version = upgrade_db(db_url, upgrade)
|
||||||
|
|
||||||
|
# THEN: the song db should have been upgraded to the latest version without errors
|
||||||
|
assert updated_to_version == latest_version, 'The song DB should have been upgrade to the latest version'
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -22,17 +22,14 @@
|
|||||||
This module contains tests for the lib submodule of the Songs plugin.
|
This module contains tests for the lib submodule of the Songs plugin.
|
||||||
"""
|
"""
|
||||||
import pytest
|
import pytest
|
||||||
from unittest import TestCase
|
|
||||||
from unittest.mock import MagicMock, patch
|
from unittest.mock import MagicMock, patch
|
||||||
|
|
||||||
from PyQt5 import QtCore
|
from PyQt5 import QtCore
|
||||||
|
|
||||||
from openlp.core.common.registry import Registry
|
from openlp.core.common.registry import Registry
|
||||||
from openlp.core.common.settings import Settings
|
|
||||||
from openlp.core.lib.serviceitem import ServiceItem
|
from openlp.core.lib.serviceitem import ServiceItem
|
||||||
from openlp.plugins.songs.lib.db import AuthorType, Song
|
from openlp.plugins.songs.lib.db import AuthorType, Song
|
||||||
from openlp.plugins.songs.lib.mediaitem import SongMediaItem
|
from openlp.plugins.songs.lib.mediaitem import SongMediaItem
|
||||||
from tests.helpers.testmixin import TestMixin
|
|
||||||
|
|
||||||
__default_settings__ = {
|
__default_settings__ = {
|
||||||
'songs/footer template': """
|
'songs/footer template': """
|
||||||
@ -92,7 +89,7 @@ ${title}<br/>
|
|||||||
|
|
||||||
|
|
||||||
@pytest.yield_fixture
|
@pytest.yield_fixture
|
||||||
def mocked_media_item(mock_settings):
|
def media_item(settings):
|
||||||
Registry().register('service_list', MagicMock())
|
Registry().register('service_list', MagicMock())
|
||||||
Registry().register('main_window', MagicMock())
|
Registry().register('main_window', MagicMock())
|
||||||
mocked_plugin = MagicMock()
|
mocked_plugin = MagicMock()
|
||||||
@ -114,505 +111,482 @@ def mocked_media_item(mock_settings):
|
|||||||
yield media_item
|
yield media_item
|
||||||
|
|
||||||
|
|
||||||
class TestMediaItem(TestCase, TestMixin):
|
def test_display_results_song(media_item):
|
||||||
"""
|
"""
|
||||||
Test the functions in the :mod:`lib` module.
|
Test displaying song search results with basic song
|
||||||
"""
|
"""
|
||||||
def setUp(self):
|
# GIVEN: Search results, plus a mocked QtListWidgetItem
|
||||||
"""
|
with patch('openlp.core.lib.QtWidgets.QListWidgetItem') as MockedQListWidgetItem, \
|
||||||
Set up the components need for all tests.
|
patch('openlp.core.lib.QtCore.Qt.UserRole') as MockedUserRole:
|
||||||
"""
|
mock_search_results = []
|
||||||
Registry.create()
|
mock_song = MagicMock()
|
||||||
Registry().register('service_list', MagicMock())
|
mock_song.id = 1
|
||||||
Registry().register('main_window', MagicMock())
|
mock_song.title = 'My Song'
|
||||||
self.mocked_plugin = MagicMock()
|
mock_song.sort_key = 'My Song'
|
||||||
with patch('openlp.core.lib.mediamanageritem.MediaManagerItem._setup'), \
|
mock_song.authors = []
|
||||||
patch('openlp.plugins.songs.forms.editsongform.EditSongForm.__init__'):
|
mock_song_temp = MagicMock()
|
||||||
self.media_item = SongMediaItem(None, self.mocked_plugin)
|
mock_song_temp.id = 2
|
||||||
self.media_item.save_auto_select_id = MagicMock()
|
mock_song_temp.title = 'My Temporary'
|
||||||
self.media_item.list_view = MagicMock()
|
mock_song_temp.sort_key = 'My Temporary'
|
||||||
self.media_item.list_view.save_auto_select_id = MagicMock()
|
mock_song_temp.authors = []
|
||||||
self.media_item.list_view.clear = MagicMock()
|
mock_author = MagicMock()
|
||||||
self.media_item.list_view.addItem = MagicMock()
|
mock_author.display_name = 'My Author'
|
||||||
self.media_item.list_view.setCurrentItem = MagicMock()
|
mock_song.authors.append(mock_author)
|
||||||
self.media_item.auto_select_id = -1
|
mock_song_temp.authors.append(mock_author)
|
||||||
self.media_item.display_songbook = False
|
mock_song.temporary = False
|
||||||
self.media_item.display_copyright_symbol = False
|
mock_song_temp.temporary = True
|
||||||
self.setup_application()
|
mock_search_results.append(mock_song)
|
||||||
self.build_settings()
|
mock_search_results.append(mock_song_temp)
|
||||||
Settings().extend_default_settings(__default_settings__)
|
mock_qlist_widget = MagicMock()
|
||||||
self.settings = self.setting
|
MockedQListWidgetItem.return_value = mock_qlist_widget
|
||||||
Registry().register('settings', self.settings)
|
media_item.auto_select_id = 1
|
||||||
QtCore.QLocale.setDefault(QtCore.QLocale('en_GB'))
|
|
||||||
|
|
||||||
def tearDown(self):
|
# WHEN: I display song search results
|
||||||
"""
|
media_item.display_results_song(mock_search_results)
|
||||||
Delete all the C++ objects at the end so that we don't have a segfault
|
|
||||||
"""
|
|
||||||
self.destroy_settings()
|
|
||||||
|
|
||||||
def test_display_results_song(self):
|
# THEN: The current list view is cleared, the widget is created, and the relevant attributes set
|
||||||
"""
|
media_item.list_view.clear.assert_called_with()
|
||||||
Test displaying song search results with basic song
|
media_item.save_auto_select_id.assert_called_with()
|
||||||
"""
|
MockedQListWidgetItem.assert_called_once_with('My Song (My Author)')
|
||||||
# GIVEN: Search results, plus a mocked QtListWidgetItem
|
mock_qlist_widget.setData.assert_called_once_with(MockedUserRole, mock_song.id)
|
||||||
with patch('openlp.core.lib.QtWidgets.QListWidgetItem') as MockedQListWidgetItem, \
|
media_item.list_view.addItem.assert_called_once_with(mock_qlist_widget)
|
||||||
patch('openlp.core.lib.QtCore.Qt.UserRole') as MockedUserRole:
|
media_item.list_view.setCurrentItem.assert_called_with(mock_qlist_widget)
|
||||||
mock_search_results = []
|
|
||||||
mock_song = MagicMock()
|
|
||||||
mock_song.id = 1
|
|
||||||
mock_song.title = 'My Song'
|
|
||||||
mock_song.sort_key = 'My Song'
|
|
||||||
mock_song.authors = []
|
|
||||||
mock_song_temp = MagicMock()
|
|
||||||
mock_song_temp.id = 2
|
|
||||||
mock_song_temp.title = 'My Temporary'
|
|
||||||
mock_song_temp.sort_key = 'My Temporary'
|
|
||||||
mock_song_temp.authors = []
|
|
||||||
mock_author = MagicMock()
|
|
||||||
mock_author.display_name = 'My Author'
|
|
||||||
mock_song.authors.append(mock_author)
|
|
||||||
mock_song_temp.authors.append(mock_author)
|
|
||||||
mock_song.temporary = False
|
|
||||||
mock_song_temp.temporary = True
|
|
||||||
mock_search_results.append(mock_song)
|
|
||||||
mock_search_results.append(mock_song_temp)
|
|
||||||
mock_qlist_widget = MagicMock()
|
|
||||||
MockedQListWidgetItem.return_value = mock_qlist_widget
|
|
||||||
self.media_item.auto_select_id = 1
|
|
||||||
|
|
||||||
# WHEN: I display song search results
|
|
||||||
self.media_item.display_results_song(mock_search_results)
|
|
||||||
|
|
||||||
# THEN: The current list view is cleared, the widget is created, and the relevant attributes set
|
def test_display_results_author(media_item):
|
||||||
self.media_item.list_view.clear.assert_called_with()
|
"""
|
||||||
self.media_item.save_auto_select_id.assert_called_with()
|
Test displaying song search results grouped by author with basic song
|
||||||
MockedQListWidgetItem.assert_called_once_with('My Song (My Author)')
|
"""
|
||||||
mock_qlist_widget.setData.assert_called_once_with(MockedUserRole, mock_song.id)
|
# GIVEN: Search results grouped by author, plus a mocked QtListWidgetItem
|
||||||
self.media_item.list_view.addItem.assert_called_once_with(mock_qlist_widget)
|
with patch('openlp.core.lib.QtWidgets.QListWidgetItem') as MockedQListWidgetItem, \
|
||||||
self.media_item.list_view.setCurrentItem.assert_called_with(mock_qlist_widget)
|
patch('openlp.core.lib.QtCore.Qt.UserRole') as MockedUserRole:
|
||||||
|
mock_search_results = []
|
||||||
|
mock_author = MagicMock()
|
||||||
|
mock_song = MagicMock()
|
||||||
|
mock_song_temp = MagicMock()
|
||||||
|
mock_author.display_name = 'My Author'
|
||||||
|
mock_author.songs = []
|
||||||
|
mock_song.id = 1
|
||||||
|
mock_song.title = 'My Song'
|
||||||
|
mock_song.sort_key = 'My Song'
|
||||||
|
mock_song.temporary = False
|
||||||
|
mock_song_temp.id = 2
|
||||||
|
mock_song_temp.title = 'My Temporary'
|
||||||
|
mock_song_temp.sort_key = 'My Temporary'
|
||||||
|
mock_song_temp.temporary = True
|
||||||
|
mock_author.songs.append(mock_song)
|
||||||
|
mock_author.songs.append(mock_song_temp)
|
||||||
|
mock_search_results.append(mock_author)
|
||||||
|
mock_qlist_widget = MagicMock()
|
||||||
|
MockedQListWidgetItem.return_value = mock_qlist_widget
|
||||||
|
|
||||||
def test_display_results_author(self):
|
# WHEN: I display song search results grouped by author
|
||||||
"""
|
media_item.display_results_author(mock_search_results)
|
||||||
Test displaying song search results grouped by author with basic song
|
|
||||||
"""
|
|
||||||
# GIVEN: Search results grouped by author, plus a mocked QtListWidgetItem
|
|
||||||
with patch('openlp.core.lib.QtWidgets.QListWidgetItem') as MockedQListWidgetItem, \
|
|
||||||
patch('openlp.core.lib.QtCore.Qt.UserRole') as MockedUserRole:
|
|
||||||
mock_search_results = []
|
|
||||||
mock_author = MagicMock()
|
|
||||||
mock_song = MagicMock()
|
|
||||||
mock_song_temp = MagicMock()
|
|
||||||
mock_author.display_name = 'My Author'
|
|
||||||
mock_author.songs = []
|
|
||||||
mock_song.id = 1
|
|
||||||
mock_song.title = 'My Song'
|
|
||||||
mock_song.sort_key = 'My Song'
|
|
||||||
mock_song.temporary = False
|
|
||||||
mock_song_temp.id = 2
|
|
||||||
mock_song_temp.title = 'My Temporary'
|
|
||||||
mock_song_temp.sort_key = 'My Temporary'
|
|
||||||
mock_song_temp.temporary = True
|
|
||||||
mock_author.songs.append(mock_song)
|
|
||||||
mock_author.songs.append(mock_song_temp)
|
|
||||||
mock_search_results.append(mock_author)
|
|
||||||
mock_qlist_widget = MagicMock()
|
|
||||||
MockedQListWidgetItem.return_value = mock_qlist_widget
|
|
||||||
|
|
||||||
# WHEN: I display song search results grouped by author
|
# THEN: The current list view is cleared, the widget is created, and the relevant attributes set
|
||||||
self.media_item.display_results_author(mock_search_results)
|
media_item.list_view.clear.assert_called_with()
|
||||||
|
MockedQListWidgetItem.assert_called_once_with('My Author (My Song)')
|
||||||
|
mock_qlist_widget.setData.assert_called_once_with(MockedUserRole, mock_song.id)
|
||||||
|
media_item.list_view.addItem.assert_called_once_with(mock_qlist_widget)
|
||||||
|
|
||||||
# THEN: The current list view is cleared, the widget is created, and the relevant attributes set
|
|
||||||
self.media_item.list_view.clear.assert_called_with()
|
|
||||||
MockedQListWidgetItem.assert_called_once_with('My Author (My Song)')
|
|
||||||
mock_qlist_widget.setData.assert_called_once_with(MockedUserRole, mock_song.id)
|
|
||||||
self.media_item.list_view.addItem.assert_called_once_with(mock_qlist_widget)
|
|
||||||
|
|
||||||
def test_display_results_book(self):
|
def test_display_results_book(media_item):
|
||||||
"""
|
"""
|
||||||
Test displaying song search results grouped by book and entry with basic song
|
Test displaying song search results grouped by book and entry with basic song
|
||||||
"""
|
"""
|
||||||
# GIVEN: Search results grouped by book and entry, plus a mocked QtListWidgetItem
|
# GIVEN: Search results grouped by book and entry, plus a mocked QtListWidgetItem
|
||||||
with patch('openlp.core.lib.QtWidgets.QListWidgetItem') as MockedQListWidgetItem, \
|
with patch('openlp.core.lib.QtWidgets.QListWidgetItem') as MockedQListWidgetItem, \
|
||||||
patch('openlp.core.lib.QtCore.Qt.UserRole') as MockedUserRole:
|
patch('openlp.core.lib.QtCore.Qt.UserRole') as MockedUserRole:
|
||||||
mock_search_results = [('1', 'My Book', 'My Song', 1)]
|
mock_search_results = [('1', 'My Book', 'My Song', 1)]
|
||||||
mock_qlist_widget = MagicMock()
|
mock_qlist_widget = MagicMock()
|
||||||
MockedQListWidgetItem.return_value = mock_qlist_widget
|
MockedQListWidgetItem.return_value = mock_qlist_widget
|
||||||
|
|
||||||
# WHEN: I display song search results grouped by book
|
|
||||||
self.media_item.display_results_book(mock_search_results)
|
|
||||||
|
|
||||||
# THEN: The current list view is cleared, the widget is created, and the relevant attributes set
|
|
||||||
self.media_item.list_view.clear.assert_called_with()
|
|
||||||
MockedQListWidgetItem.assert_called_once_with('My Book #1: My Song')
|
|
||||||
mock_qlist_widget.setData.assert_called_once_with(MockedUserRole, 1)
|
|
||||||
self.media_item.list_view.addItem.assert_called_once_with(mock_qlist_widget)
|
|
||||||
|
|
||||||
def test_songbook_natural_sorting(self):
|
|
||||||
"""
|
|
||||||
Test that songbooks are sorted naturally
|
|
||||||
"""
|
|
||||||
# GIVEN: Search results grouped by book and entry
|
|
||||||
search_results = [('2', 'Thy Book', 'Thy Song', 50),
|
|
||||||
('2', 'My Book', 'Your Song', 7),
|
|
||||||
('10', 'My Book', 'Our Song', 12),
|
|
||||||
('1', 'My Book', 'My Song', 1),
|
|
||||||
('2', 'Thy Book', 'A Song', 8)]
|
|
||||||
|
|
||||||
# WHEN: I display song search results grouped by book
|
# WHEN: I display song search results grouped by book
|
||||||
self.media_item.display_results_book(search_results)
|
media_item.display_results_book(mock_search_results)
|
||||||
|
|
||||||
# THEN: The songbooks are sorted inplace in the right (natural) order,
|
# THEN: The current list view is cleared, the widget is created, and the relevant attributes set
|
||||||
# grouped first by book, then by number, then by song title
|
media_item.list_view.clear.assert_called_with()
|
||||||
assert search_results == [('1', 'My Book', 'My Song', 1),
|
MockedQListWidgetItem.assert_called_once_with('My Book #1: My Song')
|
||||||
('2', 'My Book', 'Your Song', 7),
|
mock_qlist_widget.setData.assert_called_once_with(MockedUserRole, 1)
|
||||||
('10', 'My Book', 'Our Song', 12),
|
media_item.list_view.addItem.assert_called_once_with(mock_qlist_widget)
|
||||||
('2', 'Thy Book', 'A Song', 8),
|
|
||||||
('2', 'Thy Book', 'Thy Song', 50)]
|
|
||||||
|
|
||||||
def test_display_results_topic(self):
|
|
||||||
"""
|
|
||||||
Test displaying song search results grouped by topic with basic song
|
|
||||||
"""
|
|
||||||
# GIVEN: Search results grouped by topic, plus a mocked QtListWidgetItem
|
|
||||||
with patch('openlp.core.lib.QtWidgets.QListWidgetItem') as MockedQListWidgetItem, \
|
|
||||||
patch('openlp.core.lib.QtCore.Qt.UserRole') as MockedUserRole:
|
|
||||||
mock_search_results = []
|
|
||||||
mock_topic = MagicMock()
|
|
||||||
mock_song = MagicMock()
|
|
||||||
mock_song_temp = MagicMock()
|
|
||||||
mock_topic.name = 'My Topic'
|
|
||||||
mock_topic.songs = []
|
|
||||||
mock_song.id = 1
|
|
||||||
mock_song.title = 'My Song'
|
|
||||||
mock_song.sort_key = 'My Song'
|
|
||||||
mock_song.temporary = False
|
|
||||||
mock_song_temp.id = 2
|
|
||||||
mock_song_temp.title = 'My Temporary'
|
|
||||||
mock_song_temp.sort_key = 'My Temporary'
|
|
||||||
mock_song_temp.temporary = True
|
|
||||||
mock_topic.songs.append(mock_song)
|
|
||||||
mock_topic.songs.append(mock_song_temp)
|
|
||||||
mock_search_results.append(mock_topic)
|
|
||||||
mock_qlist_widget = MagicMock()
|
|
||||||
MockedQListWidgetItem.return_value = mock_qlist_widget
|
|
||||||
|
|
||||||
# WHEN: I display song search results grouped by topic
|
def test_songbook_natural_sorting(media_item):
|
||||||
self.media_item.display_results_topic(mock_search_results)
|
"""
|
||||||
|
Test that songbooks are sorted naturally
|
||||||
|
"""
|
||||||
|
# GIVEN: Search results grouped by book and entry
|
||||||
|
search_results = [('2', 'Thy Book', 'Thy Song', 50),
|
||||||
|
('2', 'My Book', 'Your Song', 7),
|
||||||
|
('10', 'My Book', 'Our Song', 12),
|
||||||
|
('1', 'My Book', 'My Song', 1),
|
||||||
|
('2', 'Thy Book', 'A Song', 8)]
|
||||||
|
|
||||||
# THEN: The current list view is cleared, the widget is created, and the relevant attributes set
|
# WHEN: I display song search results grouped by book
|
||||||
self.media_item.list_view.clear.assert_called_with()
|
media_item.display_results_book(search_results)
|
||||||
MockedQListWidgetItem.assert_called_once_with('My Topic (My Song)')
|
|
||||||
mock_qlist_widget.setData.assert_called_once_with(MockedUserRole, mock_song.id)
|
|
||||||
self.media_item.list_view.addItem.assert_called_once_with(mock_qlist_widget)
|
|
||||||
|
|
||||||
def test_display_results_themes(self):
|
# THEN: The songbooks are sorted inplace in the right (natural) order,
|
||||||
"""
|
# grouped first by book, then by number, then by song title
|
||||||
Test displaying song search results sorted by theme with basic song
|
assert search_results == [('1', 'My Book', 'My Song', 1),
|
||||||
"""
|
('2', 'My Book', 'Your Song', 7),
|
||||||
# GIVEN: Search results sorted by theme, plus a mocked QtListWidgetItem
|
('10', 'My Book', 'Our Song', 12),
|
||||||
with patch('openlp.core.lib.QtWidgets.QListWidgetItem') as MockedQListWidgetItem, \
|
('2', 'Thy Book', 'A Song', 8),
|
||||||
patch('openlp.core.lib.QtCore.Qt.UserRole') as MockedUserRole:
|
('2', 'Thy Book', 'Thy Song', 50)]
|
||||||
mock_search_results = []
|
|
||||||
mock_song = MagicMock()
|
|
||||||
mock_song_temp = MagicMock()
|
|
||||||
mock_song.id = 1
|
|
||||||
mock_song.title = 'My Song'
|
|
||||||
mock_song.sort_key = 'My Song'
|
|
||||||
mock_song.theme_name = 'My Theme'
|
|
||||||
mock_song.temporary = False
|
|
||||||
mock_song_temp.id = 2
|
|
||||||
mock_song_temp.title = 'My Temporary'
|
|
||||||
mock_song_temp.sort_key = 'My Temporary'
|
|
||||||
mock_song_temp.theme_name = 'My Theme'
|
|
||||||
mock_song_temp.temporary = True
|
|
||||||
mock_search_results.append(mock_song)
|
|
||||||
mock_search_results.append(mock_song_temp)
|
|
||||||
mock_qlist_widget = MagicMock()
|
|
||||||
MockedQListWidgetItem.return_value = mock_qlist_widget
|
|
||||||
|
|
||||||
# WHEN: I display song search results sorted by theme
|
|
||||||
self.media_item.display_results_themes(mock_search_results)
|
|
||||||
|
|
||||||
# THEN: The current list view is cleared, the widget is created, and the relevant attributes set
|
def test_display_results_topic(media_item):
|
||||||
self.media_item.list_view.clear.assert_called_with()
|
"""
|
||||||
MockedQListWidgetItem.assert_called_once_with('My Theme (My Song)')
|
Test displaying song search results grouped by topic with basic song
|
||||||
mock_qlist_widget.setData.assert_called_once_with(MockedUserRole, mock_song.id)
|
"""
|
||||||
self.media_item.list_view.addItem.assert_called_once_with(mock_qlist_widget)
|
# GIVEN: Search results grouped by topic, plus a mocked QtListWidgetItem
|
||||||
|
with patch('openlp.core.lib.QtWidgets.QListWidgetItem') as MockedQListWidgetItem, \
|
||||||
def test_display_results_cclinumber(self):
|
patch('openlp.core.lib.QtCore.Qt.UserRole') as MockedUserRole:
|
||||||
"""
|
mock_search_results = []
|
||||||
Test displaying song search results sorted by CCLI number with basic song
|
mock_topic = MagicMock()
|
||||||
"""
|
|
||||||
# GIVEN: Search results sorted by CCLI number, plus a mocked QtListWidgetItem
|
|
||||||
with patch('openlp.core.lib.QtWidgets.QListWidgetItem') as MockedQListWidgetItem, \
|
|
||||||
patch('openlp.core.lib.QtCore.Qt.UserRole') as MockedUserRole:
|
|
||||||
mock_search_results = []
|
|
||||||
mock_song = MagicMock()
|
|
||||||
mock_song_temp = MagicMock()
|
|
||||||
mock_song.id = 1
|
|
||||||
mock_song.title = 'My Song'
|
|
||||||
mock_song.sort_key = 'My Song'
|
|
||||||
mock_song.ccli_number = '12345'
|
|
||||||
mock_song.temporary = False
|
|
||||||
mock_song_temp.id = 2
|
|
||||||
mock_song_temp.title = 'My Temporary'
|
|
||||||
mock_song_temp.sort_key = 'My Temporary'
|
|
||||||
mock_song_temp.ccli_number = '12346'
|
|
||||||
mock_song_temp.temporary = True
|
|
||||||
mock_search_results.append(mock_song)
|
|
||||||
mock_search_results.append(mock_song_temp)
|
|
||||||
mock_qlist_widget = MagicMock()
|
|
||||||
MockedQListWidgetItem.return_value = mock_qlist_widget
|
|
||||||
|
|
||||||
# WHEN: I display song search results sorted by CCLI number
|
|
||||||
self.media_item.display_results_cclinumber(mock_search_results)
|
|
||||||
|
|
||||||
# THEN: The current list view is cleared, the widget is created, and the relevant attributes set
|
|
||||||
self.media_item.list_view.clear.assert_called_with()
|
|
||||||
MockedQListWidgetItem.assert_called_once_with('12345 (My Song)')
|
|
||||||
mock_qlist_widget.setData.assert_called_once_with(MockedUserRole, mock_song.id)
|
|
||||||
self.media_item.list_view.addItem.assert_called_once_with(mock_qlist_widget)
|
|
||||||
|
|
||||||
def test_build_song_footer_two_authors(self):
|
|
||||||
"""
|
|
||||||
Test build songs footer with basic song and two authors
|
|
||||||
"""
|
|
||||||
# GIVEN: A Song and a Service Item
|
|
||||||
mock_song = MagicMock()
|
mock_song = MagicMock()
|
||||||
|
mock_song_temp = MagicMock()
|
||||||
|
mock_topic.name = 'My Topic'
|
||||||
|
mock_topic.songs = []
|
||||||
|
mock_song.id = 1
|
||||||
mock_song.title = 'My Song'
|
mock_song.title = 'My Song'
|
||||||
mock_song.authors_songs = []
|
mock_song.sort_key = 'My Song'
|
||||||
mock_author = MagicMock()
|
mock_song.temporary = False
|
||||||
mock_author.display_name = 'my author'
|
mock_song_temp.id = 2
|
||||||
mock_author_song = MagicMock()
|
mock_song_temp.title = 'My Temporary'
|
||||||
mock_author_song.author = mock_author
|
mock_song_temp.sort_key = 'My Temporary'
|
||||||
mock_author_song.author_type = AuthorType.Music
|
mock_song_temp.temporary = True
|
||||||
mock_song.authors_songs.append(mock_author_song)
|
mock_topic.songs.append(mock_song)
|
||||||
mock_author = MagicMock()
|
mock_topic.songs.append(mock_song_temp)
|
||||||
mock_author.display_name = 'another author'
|
mock_search_results.append(mock_topic)
|
||||||
mock_author_song = MagicMock()
|
mock_qlist_widget = MagicMock()
|
||||||
mock_author_song.author = mock_author
|
MockedQListWidgetItem.return_value = mock_qlist_widget
|
||||||
mock_author_song.author_type = AuthorType.Words
|
|
||||||
mock_song.authors_songs.append(mock_author_song)
|
|
||||||
mock_author = MagicMock()
|
|
||||||
mock_author.display_name = 'translator'
|
|
||||||
mock_author_song = MagicMock()
|
|
||||||
mock_author_song.author = mock_author
|
|
||||||
mock_author_song.author_type = AuthorType.Translation
|
|
||||||
mock_song.authors_songs.append(mock_author_song)
|
|
||||||
mock_song.copyright = 'My copyright'
|
|
||||||
mock_song.songbook_entries = []
|
|
||||||
service_item = ServiceItem(None)
|
|
||||||
|
|
||||||
# WHEN: I generate the Footer with default settings
|
# WHEN: I display song search results grouped by topic
|
||||||
author_list = self.media_item.generate_footer(service_item, mock_song)
|
media_item.display_results_topic(mock_search_results)
|
||||||
|
|
||||||
# THEN: I get the following Array returned
|
# THEN: The current list view is cleared, the widget is created, and the relevant attributes set
|
||||||
assert service_item.raw_footer == ['My Song', 'Words: another author', 'Music: my author',
|
media_item.list_view.clear.assert_called_with()
|
||||||
'Translation: translator', '© My copyright'], \
|
MockedQListWidgetItem.assert_called_once_with('My Topic (My Song)')
|
||||||
'The array should be returned correctly with a song, two authors and copyright'
|
mock_qlist_widget.setData.assert_called_once_with(MockedUserRole, mock_song.id)
|
||||||
assert author_list == ['another author', 'my author', 'translator'], \
|
media_item.list_view.addItem.assert_called_once_with(mock_qlist_widget)
|
||||||
'The author list should be returned correctly with two authors'
|
|
||||||
|
|
||||||
def test_build_song_footer_base_ccli(self):
|
|
||||||
"""
|
def test_display_results_themes(media_item):
|
||||||
Test build songs footer with basic song and a CCLI number
|
"""
|
||||||
"""
|
Test displaying song search results sorted by theme with basic song
|
||||||
# GIVEN: A Song and a Service Item and a configured CCLI license
|
"""
|
||||||
|
# GIVEN: Search results sorted by theme, plus a mocked QtListWidgetItem
|
||||||
|
with patch('openlp.core.lib.QtWidgets.QListWidgetItem') as MockedQListWidgetItem, \
|
||||||
|
patch('openlp.core.lib.QtCore.Qt.UserRole') as MockedUserRole:
|
||||||
|
mock_search_results = []
|
||||||
mock_song = MagicMock()
|
mock_song = MagicMock()
|
||||||
|
mock_song_temp = MagicMock()
|
||||||
|
mock_song.id = 1
|
||||||
mock_song.title = 'My Song'
|
mock_song.title = 'My Song'
|
||||||
mock_song.copyright = 'My copyright'
|
mock_song.sort_key = 'My Song'
|
||||||
mock_song.songbook_entries = []
|
mock_song.theme_name = 'My Theme'
|
||||||
service_item = ServiceItem(None)
|
mock_song.temporary = False
|
||||||
self.settings.setValue('core/ccli number', '1234')
|
mock_song_temp.id = 2
|
||||||
|
mock_song_temp.title = 'My Temporary'
|
||||||
|
mock_song_temp.sort_key = 'My Temporary'
|
||||||
|
mock_song_temp.theme_name = 'My Theme'
|
||||||
|
mock_song_temp.temporary = True
|
||||||
|
mock_search_results.append(mock_song)
|
||||||
|
mock_search_results.append(mock_song_temp)
|
||||||
|
mock_qlist_widget = MagicMock()
|
||||||
|
MockedQListWidgetItem.return_value = mock_qlist_widget
|
||||||
|
|
||||||
# WHEN: I generate the Footer with default settings
|
# WHEN: I display song search results sorted by theme
|
||||||
self.media_item.generate_footer(service_item, mock_song)
|
media_item.display_results_themes(mock_search_results)
|
||||||
|
|
||||||
# THEN: I get the following Array returned
|
# THEN: The current list view is cleared, the widget is created, and the relevant attributes set
|
||||||
assert service_item.raw_footer == ['My Song', '© My copyright', 'CCLI License: 1234'], \
|
media_item.list_view.clear.assert_called_with()
|
||||||
'The array should be returned correctly with a song, an author, copyright and ccli'
|
MockedQListWidgetItem.assert_called_once_with('My Theme (My Song)')
|
||||||
|
mock_qlist_widget.setData.assert_called_once_with(MockedUserRole, mock_song.id)
|
||||||
|
media_item.list_view.addItem.assert_called_once_with(mock_qlist_widget)
|
||||||
|
|
||||||
# WHEN: I amend the CCLI value
|
|
||||||
self.settings.setValue('core/ccli number', '4321')
|
|
||||||
self.media_item.generate_footer(service_item, mock_song)
|
|
||||||
|
|
||||||
# THEN: I would get an amended footer string
|
def test_display_results_cclinumber(media_item):
|
||||||
assert service_item.raw_footer == ['My Song', '© My copyright', 'CCLI License: 4321'], \
|
"""
|
||||||
'The array should be returned correctly with a song, an author, copyright and amended ccli'
|
Test displaying song search results sorted by CCLI number with basic song
|
||||||
|
"""
|
||||||
def test_build_song_footer_base_songbook(self):
|
# GIVEN: Search results sorted by CCLI number, plus a mocked QtListWidgetItem
|
||||||
"""
|
with patch('openlp.core.lib.QtWidgets.QListWidgetItem') as MockedQListWidgetItem, \
|
||||||
Test build songs footer with basic song and multiple songbooks
|
patch('openlp.core.lib.QtCore.Qt.UserRole') as MockedUserRole:
|
||||||
"""
|
mock_search_results = []
|
||||||
# GIVEN: A Song and a Service Item
|
|
||||||
song = Song()
|
|
||||||
song.title = 'My Song'
|
|
||||||
song.alternate_title = ''
|
|
||||||
song.copyright = 'My copyright'
|
|
||||||
song.authors_songs = []
|
|
||||||
song.songbook_entries = []
|
|
||||||
song.alternate_title = ''
|
|
||||||
song.topics = []
|
|
||||||
song.ccli_number = ''
|
|
||||||
book1 = MagicMock()
|
|
||||||
book1.name = 'My songbook'
|
|
||||||
book2 = MagicMock()
|
|
||||||
book2.name = 'Thy songbook'
|
|
||||||
song.songbookentries = []
|
|
||||||
song.add_songbook_entry(book1, '12')
|
|
||||||
song.add_songbook_entry(book2, '502A')
|
|
||||||
service_item = ServiceItem(None)
|
|
||||||
|
|
||||||
# WHEN: I generate the Footer with default settings
|
|
||||||
self.media_item.generate_footer(service_item, song)
|
|
||||||
|
|
||||||
# THEN: The songbook should be in the footer
|
|
||||||
assert service_item.raw_footer == ['My Song', '© My copyright', 'My songbook #12, Thy songbook #502A']
|
|
||||||
|
|
||||||
def test_build_song_footer_copyright_enabled(self):
|
|
||||||
"""
|
|
||||||
Test building song footer with displaying the copyright symbol
|
|
||||||
"""
|
|
||||||
# GIVEN: A Song and a Service Item; displaying the copyright symbol is enabled
|
|
||||||
self.media_item.display_copyright_symbol = True
|
|
||||||
mock_song = MagicMock()
|
mock_song = MagicMock()
|
||||||
|
mock_song_temp = MagicMock()
|
||||||
|
mock_song.id = 1
|
||||||
mock_song.title = 'My Song'
|
mock_song.title = 'My Song'
|
||||||
mock_song.copyright = 'My copyright'
|
mock_song.sort_key = 'My Song'
|
||||||
mock_song.songbook_entries = []
|
mock_song.ccli_number = '12345'
|
||||||
service_item = ServiceItem(None)
|
mock_song.temporary = False
|
||||||
|
mock_song_temp.id = 2
|
||||||
|
mock_song_temp.title = 'My Temporary'
|
||||||
|
mock_song_temp.sort_key = 'My Temporary'
|
||||||
|
mock_song_temp.ccli_number = '12346'
|
||||||
|
mock_song_temp.temporary = True
|
||||||
|
mock_search_results.append(mock_song)
|
||||||
|
mock_search_results.append(mock_song_temp)
|
||||||
|
mock_qlist_widget = MagicMock()
|
||||||
|
MockedQListWidgetItem.return_value = mock_qlist_widget
|
||||||
|
|
||||||
# WHEN: I generate the Footer with default settings
|
# WHEN: I display song search results sorted by CCLI number
|
||||||
self.media_item.generate_footer(service_item, mock_song)
|
media_item.display_results_cclinumber(mock_search_results)
|
||||||
|
|
||||||
# THEN: The copyright symbol should be in the footer
|
# THEN: The current list view is cleared, the widget is created, and the relevant attributes set
|
||||||
assert service_item.raw_footer == ['My Song', '© My copyright']
|
media_item.list_view.clear.assert_called_with()
|
||||||
|
MockedQListWidgetItem.assert_called_once_with('12345 (My Song)')
|
||||||
def test_build_song_footer_copyright_disabled(self):
|
mock_qlist_widget.setData.assert_called_once_with(MockedUserRole, mock_song.id)
|
||||||
"""
|
media_item.list_view.addItem.assert_called_once_with(mock_qlist_widget)
|
||||||
Test building song footer without displaying the copyright symbol
|
|
||||||
"""
|
|
||||||
# GIVEN: A Song and a Service Item; displaying the copyright symbol should be disabled by default
|
|
||||||
mock_song = MagicMock()
|
|
||||||
mock_song.title = 'My Song'
|
|
||||||
mock_song.copyright = 'My copyright'
|
|
||||||
mock_song.songbook_entries = []
|
|
||||||
service_item = ServiceItem(None)
|
|
||||||
|
|
||||||
# WHEN: I generate the Footer with default settings
|
|
||||||
self.media_item.generate_footer(service_item, mock_song)
|
|
||||||
|
|
||||||
# THEN: The copyright symbol should not be in the footer
|
|
||||||
assert service_item.raw_footer == ['My Song', '© My copyright']
|
|
||||||
|
|
||||||
def test_authors_match(self):
|
|
||||||
"""
|
|
||||||
Test the author matching when importing a song from a service
|
|
||||||
"""
|
|
||||||
# GIVEN: A song and a string with authors
|
|
||||||
song = MagicMock()
|
|
||||||
song.authors = []
|
|
||||||
author = MagicMock()
|
|
||||||
author.display_name = "Hans Wurst"
|
|
||||||
song.authors.append(author)
|
|
||||||
author2 = MagicMock()
|
|
||||||
author2.display_name = "Max Mustermann"
|
|
||||||
song.authors.append(author2)
|
|
||||||
# There are occasions where an author appears twice in a song (with different types).
|
|
||||||
# We need to make sure that this case works (lp#1313538)
|
|
||||||
author3 = MagicMock()
|
|
||||||
author3.display_name = "Max Mustermann"
|
|
||||||
song.authors.append(author3)
|
|
||||||
authors_str = "Hans Wurst, Max Mustermann, Max Mustermann"
|
|
||||||
|
|
||||||
# WHEN: Checking for matching
|
|
||||||
result = self.media_item._authors_match(song, authors_str)
|
|
||||||
|
|
||||||
# THEN: They should match
|
|
||||||
assert result is True, "Authors should match"
|
|
||||||
|
|
||||||
def test_authors_dont_match(self):
|
|
||||||
# GIVEN: A song and a string with authors
|
|
||||||
song = MagicMock()
|
|
||||||
song.authors = []
|
|
||||||
author = MagicMock()
|
|
||||||
author.display_name = "Hans Wurst"
|
|
||||||
song.authors.append(author)
|
|
||||||
author2 = MagicMock()
|
|
||||||
author2.display_name = "Max Mustermann"
|
|
||||||
song.authors.append(author2)
|
|
||||||
# There are occasions where an author appears twice in a song (with different types).
|
|
||||||
# We need to make sure that this case works (lp#1313538)
|
|
||||||
author3 = MagicMock()
|
|
||||||
author3.display_name = "Max Mustermann"
|
|
||||||
song.authors.append(author3)
|
|
||||||
|
|
||||||
# WHEN: An author is missing in the string
|
|
||||||
authors_str = "Hans Wurst, Max Mustermann"
|
|
||||||
result = self.media_item._authors_match(song, authors_str)
|
|
||||||
|
|
||||||
# THEN: They should not match
|
|
||||||
assert result is False, "Authors should not match"
|
|
||||||
|
|
||||||
def test_build_remote_search(self):
|
|
||||||
"""
|
|
||||||
Test results for the remote search api
|
|
||||||
"""
|
|
||||||
# GIVEN: A Song and a search a JSON array should be returned.
|
|
||||||
mock_song = MagicMock()
|
|
||||||
mock_song.id = 123
|
|
||||||
mock_song.title = 'My Song'
|
|
||||||
mock_song.search_title = 'My Song'
|
|
||||||
mock_song.alternate_title = 'My alternative'
|
|
||||||
self.media_item.search_entire = MagicMock()
|
|
||||||
self.media_item.search_entire.return_value = [mock_song]
|
|
||||||
|
|
||||||
# WHEN: I process a search
|
|
||||||
search_results = self.media_item.search('My Song', False)
|
|
||||||
|
|
||||||
# THEN: The correct formatted results are returned
|
|
||||||
assert search_results == [[123, 'My Song', 'My alternative']]
|
|
||||||
|
|
||||||
@patch('openlp.plugins.songs.lib.mediaitem.Book')
|
|
||||||
@patch('openlp.plugins.songs.lib.mediaitem.SongBookEntry')
|
|
||||||
@patch('openlp.plugins.songs.lib.mediaitem.Song')
|
|
||||||
@patch('openlp.plugins.songs.lib.mediaitem.or_')
|
|
||||||
def test_entire_song_search(self, mocked_or, MockedSong, MockedSongBookEntry, MockedBook):
|
|
||||||
"""
|
|
||||||
Test that searching the entire song does the right queries
|
|
||||||
"""
|
|
||||||
# GIVEN: A song media item, a keyword and some mocks
|
|
||||||
keyword = 'Jesus'
|
|
||||||
mocked_or.side_effect = lambda a, b, c, d, e: ' '.join([a, b, c, d, e])
|
|
||||||
MockedSong.search_title.like.side_effect = lambda a: a
|
|
||||||
MockedSong.search_lyrics.like.side_effect = lambda a: a
|
|
||||||
MockedSong.comments.like.side_effect = lambda a: a
|
|
||||||
MockedSongBookEntry.entry.like.side_effect = lambda a: a
|
|
||||||
MockedBook.name.like.side_effect = lambda a: a
|
|
||||||
|
|
||||||
# WHEN: search_entire_song() is called with the keyword
|
|
||||||
self.media_item.search_entire(keyword)
|
|
||||||
|
|
||||||
# THEN: The correct calls were made
|
|
||||||
MockedSong.search_title.like.assert_called_once_with('%jesus%')
|
|
||||||
MockedSong.search_lyrics.like.assert_called_once_with('%jesus%')
|
|
||||||
MockedSong.comments.like.assert_called_once_with('%jesus%')
|
|
||||||
MockedSongBookEntry.entry.like.assert_called_once_with('%jesus%')
|
|
||||||
MockedBook.name.like.assert_called_once_with('%jesus%')
|
|
||||||
mocked_or.assert_called_once_with('%jesus%', '%jesus%', '%jesus%', '%jesus%', '%jesus%')
|
|
||||||
self.mocked_plugin.manager.session.query.assert_called_once_with(MockedSong)
|
|
||||||
|
|
||||||
assert self.mocked_plugin.manager.session.query.mock_calls[4][0] == '().join().join().filter().all'
|
|
||||||
|
|
||||||
|
|
||||||
def test_build_song_footer_one_author_show_written_by(mocked_media_item):
|
def test_build_song_footer_two_authors(media_item):
|
||||||
|
"""
|
||||||
|
Test build songs footer with basic song and two authors
|
||||||
|
"""
|
||||||
|
# GIVEN: A Song and a Service Item
|
||||||
|
mock_song = MagicMock()
|
||||||
|
mock_song.title = 'My Song'
|
||||||
|
mock_song.authors_songs = []
|
||||||
|
mock_author = MagicMock()
|
||||||
|
mock_author.display_name = 'my author'
|
||||||
|
mock_author_song = MagicMock()
|
||||||
|
mock_author_song.author = mock_author
|
||||||
|
mock_author_song.author_type = AuthorType.Music
|
||||||
|
mock_song.authors_songs.append(mock_author_song)
|
||||||
|
mock_author = MagicMock()
|
||||||
|
mock_author.display_name = 'another author'
|
||||||
|
mock_author_song = MagicMock()
|
||||||
|
mock_author_song.author = mock_author
|
||||||
|
mock_author_song.author_type = AuthorType.Words
|
||||||
|
mock_song.authors_songs.append(mock_author_song)
|
||||||
|
mock_author = MagicMock()
|
||||||
|
mock_author.display_name = 'translator'
|
||||||
|
mock_author_song = MagicMock()
|
||||||
|
mock_author_song.author = mock_author
|
||||||
|
mock_author_song.author_type = AuthorType.Translation
|
||||||
|
mock_song.authors_songs.append(mock_author_song)
|
||||||
|
mock_song.copyright = 'My copyright'
|
||||||
|
mock_song.songbook_entries = []
|
||||||
|
service_item = ServiceItem(None)
|
||||||
|
|
||||||
|
# WHEN: I generate the Footer with default settings
|
||||||
|
author_list = media_item.generate_footer(service_item, mock_song)
|
||||||
|
|
||||||
|
# THEN: I get the following Array returned
|
||||||
|
assert service_item.raw_footer == ['My Song', 'Words: another author', 'Music: my author',
|
||||||
|
'Translation: translator', '© My copyright'], \
|
||||||
|
'The array should be returned correctly with a song, two authors and copyright'
|
||||||
|
assert author_list == ['another author', 'my author', 'translator'], \
|
||||||
|
'The author list should be returned correctly with two authors'
|
||||||
|
|
||||||
|
|
||||||
|
def test_build_song_footer_base_ccli(media_item):
|
||||||
|
"""
|
||||||
|
Test build songs footer with basic song and a CCLI number
|
||||||
|
"""
|
||||||
|
# GIVEN: A Song and a Service Item and a configured CCLI license
|
||||||
|
mock_song = MagicMock()
|
||||||
|
mock_song.title = 'My Song'
|
||||||
|
mock_song.copyright = 'My copyright'
|
||||||
|
mock_song.songbook_entries = []
|
||||||
|
service_item = ServiceItem(None)
|
||||||
|
media_item.settings.setValue('core/ccli number', '1234')
|
||||||
|
|
||||||
|
# WHEN: I generate the Footer with default settings
|
||||||
|
media_item.generate_footer(service_item, mock_song)
|
||||||
|
|
||||||
|
# THEN: I get the following Array returned
|
||||||
|
assert service_item.raw_footer == ['My Song', '© My copyright', 'CCLI License: 1234'], \
|
||||||
|
'The array should be returned correctly with a song, an author, copyright and ccli'
|
||||||
|
|
||||||
|
# WHEN: I amend the CCLI value
|
||||||
|
media_item.settings.setValue('core/ccli number', '4321')
|
||||||
|
media_item.generate_footer(service_item, mock_song)
|
||||||
|
|
||||||
|
# THEN: I would get an amended footer string
|
||||||
|
assert service_item.raw_footer == ['My Song', '© My copyright', 'CCLI License: 4321'], \
|
||||||
|
'The array should be returned correctly with a song, an author, copyright and amended ccli'
|
||||||
|
|
||||||
|
|
||||||
|
def test_build_song_footer_base_songbook(media_item):
|
||||||
|
"""
|
||||||
|
Test build songs footer with basic song and multiple songbooks
|
||||||
|
"""
|
||||||
|
# GIVEN: A Song and a Service Item
|
||||||
|
song = Song()
|
||||||
|
song.title = 'My Song'
|
||||||
|
song.alternate_title = ''
|
||||||
|
song.copyright = 'My copyright'
|
||||||
|
song.authors_songs = []
|
||||||
|
song.songbook_entries = []
|
||||||
|
song.alternate_title = ''
|
||||||
|
song.topics = []
|
||||||
|
song.ccli_number = ''
|
||||||
|
book1 = MagicMock()
|
||||||
|
book1.name = 'My songbook'
|
||||||
|
book2 = MagicMock()
|
||||||
|
book2.name = 'Thy songbook'
|
||||||
|
song.songbookentries = []
|
||||||
|
song.add_songbook_entry(book1, '12')
|
||||||
|
song.add_songbook_entry(book2, '502A')
|
||||||
|
service_item = ServiceItem(None)
|
||||||
|
|
||||||
|
# WHEN: I generate the Footer with default settings
|
||||||
|
media_item.generate_footer(service_item, song)
|
||||||
|
|
||||||
|
# THEN: The songbook should be in the footer
|
||||||
|
assert service_item.raw_footer == ['My Song', '© My copyright', 'My songbook #12, Thy songbook #502A']
|
||||||
|
|
||||||
|
|
||||||
|
def test_build_song_footer_copyright_enabled(media_item):
|
||||||
|
"""
|
||||||
|
Test building song footer with displaying the copyright symbol
|
||||||
|
"""
|
||||||
|
# GIVEN: A Song and a Service Item; displaying the copyright symbol is enabled
|
||||||
|
media_item.display_copyright_symbol = True
|
||||||
|
mock_song = MagicMock()
|
||||||
|
mock_song.title = 'My Song'
|
||||||
|
mock_song.copyright = 'My copyright'
|
||||||
|
mock_song.songbook_entries = []
|
||||||
|
service_item = ServiceItem(None)
|
||||||
|
|
||||||
|
# WHEN: I generate the Footer with default settings
|
||||||
|
media_item.generate_footer(service_item, mock_song)
|
||||||
|
|
||||||
|
# THEN: The copyright symbol should be in the footer
|
||||||
|
assert service_item.raw_footer == ['My Song', '© My copyright']
|
||||||
|
|
||||||
|
|
||||||
|
def test_build_song_footer_copyright_disabled(media_item):
|
||||||
|
"""
|
||||||
|
Test building song footer without displaying the copyright symbol
|
||||||
|
"""
|
||||||
|
# GIVEN: A Song and a Service Item; displaying the copyright symbol should be disabled by default
|
||||||
|
mock_song = MagicMock()
|
||||||
|
mock_song.title = 'My Song'
|
||||||
|
mock_song.copyright = 'My copyright'
|
||||||
|
mock_song.songbook_entries = []
|
||||||
|
service_item = ServiceItem(None)
|
||||||
|
|
||||||
|
# WHEN: I generate the Footer with default settings
|
||||||
|
media_item.generate_footer(service_item, mock_song)
|
||||||
|
|
||||||
|
# THEN: The copyright symbol should not be in the footer
|
||||||
|
assert service_item.raw_footer == ['My Song', '© My copyright']
|
||||||
|
|
||||||
|
|
||||||
|
def test_authors_match(media_item):
|
||||||
|
"""
|
||||||
|
Test the author matching when importing a song from a service
|
||||||
|
"""
|
||||||
|
# GIVEN: A song and a string with authors
|
||||||
|
song = MagicMock()
|
||||||
|
song.authors = []
|
||||||
|
author = MagicMock()
|
||||||
|
author.display_name = "Hans Wurst"
|
||||||
|
song.authors.append(author)
|
||||||
|
author2 = MagicMock()
|
||||||
|
author2.display_name = "Max Mustermann"
|
||||||
|
song.authors.append(author2)
|
||||||
|
# There are occasions where an author appears twice in a song (with different types).
|
||||||
|
# We need to make sure that this case works (lp#1313538)
|
||||||
|
author3 = MagicMock()
|
||||||
|
author3.display_name = "Max Mustermann"
|
||||||
|
song.authors.append(author3)
|
||||||
|
authors_str = "Hans Wurst, Max Mustermann, Max Mustermann"
|
||||||
|
|
||||||
|
# WHEN: Checking for matching
|
||||||
|
result = media_item._authors_match(song, authors_str)
|
||||||
|
|
||||||
|
# THEN: They should match
|
||||||
|
assert result is True, "Authors should match"
|
||||||
|
|
||||||
|
|
||||||
|
def test_authors_dont_match(media_item):
|
||||||
|
# GIVEN: A song and a string with authors
|
||||||
|
song = MagicMock()
|
||||||
|
song.authors = []
|
||||||
|
author = MagicMock()
|
||||||
|
author.display_name = "Hans Wurst"
|
||||||
|
song.authors.append(author)
|
||||||
|
author2 = MagicMock()
|
||||||
|
author2.display_name = "Max Mustermann"
|
||||||
|
song.authors.append(author2)
|
||||||
|
# There are occasions where an author appears twice in a song (with different types).
|
||||||
|
# We need to make sure that this case works (lp#1313538)
|
||||||
|
author3 = MagicMock()
|
||||||
|
author3.display_name = "Max Mustermann"
|
||||||
|
song.authors.append(author3)
|
||||||
|
|
||||||
|
# WHEN: An author is missing in the string
|
||||||
|
authors_str = "Hans Wurst, Max Mustermann"
|
||||||
|
result = media_item._authors_match(song, authors_str)
|
||||||
|
|
||||||
|
# THEN: They should not match
|
||||||
|
assert result is False, "Authors should not match"
|
||||||
|
|
||||||
|
|
||||||
|
def test_build_remote_search(media_item):
|
||||||
|
"""
|
||||||
|
Test results for the remote search api
|
||||||
|
"""
|
||||||
|
# GIVEN: A Song and a search a JSON array should be returned.
|
||||||
|
mock_song = MagicMock()
|
||||||
|
mock_song.id = 123
|
||||||
|
mock_song.title = 'My Song'
|
||||||
|
mock_song.search_title = 'My Song'
|
||||||
|
mock_song.alternate_title = 'My alternative'
|
||||||
|
media_item.search_entire = MagicMock()
|
||||||
|
media_item.search_entire.return_value = [mock_song]
|
||||||
|
|
||||||
|
# WHEN: I process a search
|
||||||
|
search_results = media_item.search('My Song', False)
|
||||||
|
|
||||||
|
# THEN: The correct formatted results are returned
|
||||||
|
assert search_results == [[123, 'My Song', 'My alternative']]
|
||||||
|
|
||||||
|
|
||||||
|
@patch('openlp.plugins.songs.lib.mediaitem.Book')
|
||||||
|
@patch('openlp.plugins.songs.lib.mediaitem.SongBookEntry')
|
||||||
|
@patch('openlp.plugins.songs.lib.mediaitem.Song')
|
||||||
|
@patch('openlp.plugins.songs.lib.mediaitem.or_')
|
||||||
|
def test_entire_song_search(mocked_or, MockedSong, MockedSongBookEntry, MockedBook, media_item):
|
||||||
|
"""
|
||||||
|
Test that searching the entire song does the right queries
|
||||||
|
"""
|
||||||
|
# GIVEN: A song media item, a keyword and some mocks
|
||||||
|
keyword = 'Jesus'
|
||||||
|
mocked_or.side_effect = lambda a, b, c, d, e: ' '.join([a, b, c, d, e])
|
||||||
|
MockedSong.search_title.like.side_effect = lambda a: a
|
||||||
|
MockedSong.search_lyrics.like.side_effect = lambda a: a
|
||||||
|
MockedSong.comments.like.side_effect = lambda a: a
|
||||||
|
MockedSongBookEntry.entry.like.side_effect = lambda a: a
|
||||||
|
MockedBook.name.like.side_effect = lambda a: a
|
||||||
|
|
||||||
|
# WHEN: search_entire_song() is called with the keyword
|
||||||
|
media_item.search_entire(keyword)
|
||||||
|
|
||||||
|
# THEN: The correct calls were made
|
||||||
|
MockedSong.search_title.like.assert_called_once_with('%jesus%')
|
||||||
|
MockedSong.search_lyrics.like.assert_called_once_with('%jesus%')
|
||||||
|
MockedSong.comments.like.assert_called_once_with('%jesus%')
|
||||||
|
MockedSongBookEntry.entry.like.assert_called_once_with('%jesus%')
|
||||||
|
MockedBook.name.like.assert_called_once_with('%jesus%')
|
||||||
|
mocked_or.assert_called_once_with('%jesus%', '%jesus%', '%jesus%', '%jesus%', '%jesus%')
|
||||||
|
media_item.plugin.manager.session.query.assert_called_once_with(MockedSong)
|
||||||
|
|
||||||
|
assert media_item.plugin.manager.session.query.mock_calls[4][0] == '().join().join().filter().all'
|
||||||
|
|
||||||
|
|
||||||
|
def test_build_song_footer_one_author_show_written_by(media_item):
|
||||||
"""
|
"""
|
||||||
Test build songs footer with basic song and one author
|
Test build songs footer with basic song and one author
|
||||||
"""
|
"""
|
||||||
# GIVEN: A Song and a Service Item, mocked settings
|
# GIVEN: A Song and a Service Item, mocked settings
|
||||||
|
media_item.settings.setValue('core/ccli number', "0")
|
||||||
mocked_media_item.settings.value.side_effect = [False, "", "0"]
|
media_item.settings.setValue('songs/footer template', "")
|
||||||
|
|
||||||
with patch('mako.template.Template.render_unicode') as MockedRenderer:
|
with patch('mako.template.Template.render_unicode') as MockedRenderer:
|
||||||
mock_song = MagicMock()
|
mock_song = MagicMock()
|
||||||
mock_song.title = 'My Song'
|
mock_song.title = 'My Song'
|
||||||
@ -629,7 +603,7 @@ def test_build_song_footer_one_author_show_written_by(mocked_media_item):
|
|||||||
service_item = ServiceItem(None)
|
service_item = ServiceItem(None)
|
||||||
|
|
||||||
# WHEN: I generate the Footer with default settings
|
# WHEN: I generate the Footer with default settings
|
||||||
author_list = mocked_media_item.generate_footer(service_item, mock_song)
|
author_list = media_item.generate_footer(service_item, mock_song)
|
||||||
|
|
||||||
# THEN: The mako function was called with the following arguments
|
# THEN: The mako function was called with the following arguments
|
||||||
args = {'authors_translation': [], 'authors_music_label': 'Music',
|
args = {'authors_translation': [], 'authors_music_label': 'Music',
|
||||||
|
@ -21,73 +21,70 @@
|
|||||||
"""
|
"""
|
||||||
This module contains tests for the SongFormat class
|
This module contains tests for the SongFormat class
|
||||||
"""
|
"""
|
||||||
from unittest import TestCase
|
|
||||||
|
|
||||||
from openlp.plugins.songs.lib.importer import SongFormat
|
from openlp.plugins.songs.lib.importer import SongFormat
|
||||||
|
|
||||||
|
|
||||||
class TestSongFormat(TestCase):
|
def test_get_format_list():
|
||||||
"""
|
"""
|
||||||
Test the functions in the :class:`SongFormat` class.
|
Test that get_format_list() returns all available formats
|
||||||
"""
|
"""
|
||||||
|
# GIVEN: The SongFormat class
|
||||||
|
# WHEN: Retrieving the format list
|
||||||
|
# THEN: All SongFormats should be returned
|
||||||
|
assert len(SongFormat.get_format_list()) == len(SongFormat.__attributes__), \
|
||||||
|
"The returned SongFormats don't match the stored ones"
|
||||||
|
|
||||||
def test_get_format_list(self):
|
|
||||||
"""
|
|
||||||
Test that get_format_list() returns all available formats
|
|
||||||
"""
|
|
||||||
# GIVEN: The SongFormat class
|
|
||||||
# WHEN: Retrieving the format list
|
|
||||||
# THEN: All SongFormats should be returned
|
|
||||||
assert len(SongFormat.get_format_list()) == len(SongFormat.__attributes__), \
|
|
||||||
"The returned SongFormats don't match the stored ones"
|
|
||||||
|
|
||||||
def test_get_attributed_no_attributes(self):
|
def test_get_attributed_no_attributes():
|
||||||
"""
|
"""
|
||||||
Test that SongFormat.get(song_format) returns all attributes associated with the given song_format
|
Test that SongFormat.get(song_format) returns all attributes associated with the given song_format
|
||||||
"""
|
"""
|
||||||
# GIVEN: A SongFormat
|
# GIVEN: A SongFormat
|
||||||
# WHEN: Retrieving all attributes of a SongFormat
|
# WHEN: Retrieving all attributes of a SongFormat
|
||||||
for song_format in SongFormat.get_format_list():
|
for song_format in SongFormat.get_format_list():
|
||||||
# THEN: All attributes associated with the SongFormat should be returned
|
# THEN: All attributes associated with the SongFormat should be returned
|
||||||
assert SongFormat.get(song_format) == SongFormat.__attributes__[song_format], \
|
assert SongFormat.get(song_format) == SongFormat.__attributes__[song_format], \
|
||||||
"The returned attributes don't match the stored ones"
|
"The returned attributes don't match the stored ones"
|
||||||
|
|
||||||
def test_get_attributed_single_attribute(self):
|
|
||||||
"""
|
|
||||||
Test that SongFormat.get(song_format, attribute) returns only one -and the correct- attribute
|
|
||||||
"""
|
|
||||||
# GIVEN: A SongFormat
|
|
||||||
for song_format in SongFormat.get_format_list():
|
|
||||||
# WHEN: Retrieving an attribute that overrides the default values
|
|
||||||
for attribute in SongFormat.get(song_format).keys():
|
|
||||||
# THEN: Return the attribute
|
|
||||||
assert SongFormat.get(song_format, attribute) == SongFormat.get(song_format)[attribute], \
|
|
||||||
"The returned attribute doesn't match the stored one"
|
|
||||||
# WHEN: Retrieving an attribute that was not overridden
|
|
||||||
for attribute in SongFormat.__defaults__.keys():
|
|
||||||
if attribute not in SongFormat.get(song_format).keys():
|
|
||||||
# THEN: Return the default value
|
|
||||||
assert SongFormat.get(song_format, attribute) == SongFormat.__defaults__[attribute], \
|
|
||||||
"The returned attribute does not match the default values stored"
|
|
||||||
|
|
||||||
def test_get_attributed_multiple_attributes(self):
|
def test_get_attributed_single_attribute():
|
||||||
"""
|
"""
|
||||||
Test that multiple attributes can be retrieved for a song_format
|
Test that SongFormat.get(song_format, attribute) returns only one -and the correct- attribute
|
||||||
"""
|
"""
|
||||||
# GIVEN: A SongFormat
|
# GIVEN: A SongFormat
|
||||||
# WHEN: Retrieving multiple attributes at the same time
|
for song_format in SongFormat.get_format_list():
|
||||||
for song_format in SongFormat.get_format_list():
|
# WHEN: Retrieving an attribute that overrides the default values
|
||||||
# THEN: Return all attributes that were specified
|
for attribute in SongFormat.get(song_format).keys():
|
||||||
assert len(SongFormat.get(song_format, 'canDisable', 'availability')) == 2, \
|
# THEN: Return the attribute
|
||||||
"Did not return the correct number of attributes when retrieving multiple attributes at once"
|
assert SongFormat.get(song_format, attribute) == SongFormat.get(song_format)[attribute], \
|
||||||
|
"The returned attribute doesn't match the stored one"
|
||||||
|
# WHEN: Retrieving an attribute that was not overridden
|
||||||
|
for attribute in SongFormat.__defaults__.keys():
|
||||||
|
if attribute not in SongFormat.get(song_format).keys():
|
||||||
|
# THEN: Return the default value
|
||||||
|
assert SongFormat.get(song_format, attribute) == SongFormat.__defaults__[attribute], \
|
||||||
|
"The returned attribute does not match the default values stored"
|
||||||
|
|
||||||
def test_get_format_list_returns_ordered_list(self):
|
|
||||||
"""
|
def test_get_attributed_multiple_attributes():
|
||||||
Test that get_format_list() returns a list that is ordered
|
"""
|
||||||
according to the order specified in SongFormat
|
Test that multiple attributes can be retrieved for a song_format
|
||||||
"""
|
"""
|
||||||
# GIVEN: The SongFormat class
|
# GIVEN: A SongFormat
|
||||||
# WHEN: Retrieving all formats
|
# WHEN: Retrieving multiple attributes at the same time
|
||||||
# THEN: The returned list should be sorted according to the ordering defined in SongFormat
|
for song_format in SongFormat.get_format_list():
|
||||||
assert sorted(SongFormat.get_format_list()) == SongFormat.get_format_list(), \
|
# THEN: Return all attributes that were specified
|
||||||
"The list returned should be sorted according to the ordering in SongFormat"
|
assert len(SongFormat.get(song_format, 'canDisable', 'availability')) == 2, \
|
||||||
|
"Did not return the correct number of attributes when retrieving multiple attributes at once"
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_format_list_returns_ordered_list():
|
||||||
|
"""
|
||||||
|
Test that get_format_list() returns a list that is ordered
|
||||||
|
according to the order specified in SongFormat
|
||||||
|
"""
|
||||||
|
# GIVEN: The SongFormat class
|
||||||
|
# WHEN: Retrieving all formats
|
||||||
|
# THEN: The returned list should be sorted according to the ordering defined in SongFormat
|
||||||
|
assert sorted(SongFormat.get_format_list()) == SongFormat.get_format_list(), \
|
||||||
|
"The list returned should be sorted according to the ordering in SongFormat"
|
||||||
|
@ -21,14 +21,13 @@
|
|||||||
"""
|
"""
|
||||||
This module contains tests for the lib submodule of the Images plugin.
|
This module contains tests for the lib submodule of the Images plugin.
|
||||||
"""
|
"""
|
||||||
from unittest import TestCase
|
import pytest
|
||||||
from unittest.mock import MagicMock, patch
|
from unittest.mock import MagicMock, patch
|
||||||
|
|
||||||
from PyQt5 import QtCore, QtWidgets
|
from PyQt5 import QtCore
|
||||||
|
|
||||||
from openlp.core.common.registry import Registry
|
from openlp.core.common.registry import Registry
|
||||||
from openlp.plugins.songs.lib.songstab import SongsTab
|
from openlp.plugins.songs.lib.songstab import SongsTab
|
||||||
from tests.helpers.testmixin import TestMixin
|
|
||||||
|
|
||||||
__default_settings__ = {
|
__default_settings__ = {
|
||||||
'songs/footer template': """${title}""",
|
'songs/footer template': """${title}""",
|
||||||
@ -36,175 +35,167 @@ __default_settings__ = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class TestSongTab(TestCase, TestMixin):
|
@pytest.fixture()
|
||||||
|
def form(settings):
|
||||||
|
Registry().register('settings_form', MagicMock())
|
||||||
|
Registry().get('settings').extend_default_settings(__default_settings__)
|
||||||
|
frm = SongsTab(None, 'Songs', None, None)
|
||||||
|
frm.settings_form.register_post_process = MagicMock()
|
||||||
|
return frm
|
||||||
|
|
||||||
|
|
||||||
|
def test_german_notation_on_load(form):
|
||||||
"""
|
"""
|
||||||
This is a test case to test various methods in the ImageTab.
|
Test the corrent notation is selected on load
|
||||||
"""
|
"""
|
||||||
|
# GIVEN: German notation in the settings
|
||||||
|
form.settings.setValue('songs/chord notation', 'german')
|
||||||
|
# WHEN: Load is invoked
|
||||||
|
form.load()
|
||||||
|
# THEN: The german radio button should be checked
|
||||||
|
assert form.german_notation_radio_button.isChecked() is True
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
"""
|
|
||||||
Create the UI
|
|
||||||
"""
|
|
||||||
Registry.create()
|
|
||||||
Registry().register('settings_form', MagicMock())
|
|
||||||
self.setup_application()
|
|
||||||
self.build_settings()
|
|
||||||
Registry().register('settings', self.setting)
|
|
||||||
self.setting.extend_default_settings(__default_settings__)
|
|
||||||
self.parent = QtWidgets.QMainWindow()
|
|
||||||
self.form = SongsTab(self.parent, 'Songs', None, None)
|
|
||||||
self.form.settings_form.register_post_process = MagicMock()
|
|
||||||
|
|
||||||
def tearDown(self):
|
def test_neolatin_notation_on_load(form):
|
||||||
"""
|
"""
|
||||||
Delete all the C++ objects at the end so that we don't have a segfault
|
Test the corrent notation is selected on load
|
||||||
"""
|
"""
|
||||||
del self.parent
|
# GIVEN: neo-latin notation in the settings
|
||||||
del self.form
|
form.settings.setValue('songs/chord notation', 'neo-latin')
|
||||||
self.destroy_settings()
|
# WHEN: Load is invoked
|
||||||
|
form.load()
|
||||||
|
# THEN: The neo-latin radio button should be checked
|
||||||
|
assert form.neolatin_notation_radio_button.isChecked() is True
|
||||||
|
|
||||||
def test_german_notation_on_load(self):
|
|
||||||
"""
|
|
||||||
Test the corrent notation is selected on load
|
|
||||||
"""
|
|
||||||
# GIVEN: German notation in the settings
|
|
||||||
self.setting.setValue('songs/chord notation', 'german')
|
|
||||||
# WHEN: Load is invoked
|
|
||||||
self.form.load()
|
|
||||||
# THEN: The german radio button should be checked
|
|
||||||
assert self.form.german_notation_radio_button.isChecked() is True
|
|
||||||
|
|
||||||
def test_neolatin_notation_on_load(self):
|
def test_invalid_notation_on_load(form):
|
||||||
"""
|
"""
|
||||||
Test the corrent notation is selected on load
|
Test the invalid notation in settings reverts to english
|
||||||
"""
|
"""
|
||||||
# GIVEN: neo-latin notation in the settings
|
# GIVEN: gibberish notation in the settings
|
||||||
self.setting.setValue('songs/chord notation', 'neo-latin')
|
form.settings.setValue('songs/chord notation', 'gibberish')
|
||||||
# WHEN: Load is invoked
|
# WHEN: Load is invoked
|
||||||
self.form.load()
|
form.load()
|
||||||
# THEN: The neo-latin radio button should be checked
|
# THEN: The english radio button should be checked
|
||||||
assert self.form.neolatin_notation_radio_button.isChecked() is True
|
assert form.english_notation_radio_button.isChecked() is True
|
||||||
|
|
||||||
def test_invalid_notation_on_load(self):
|
|
||||||
"""
|
|
||||||
Test the invalid notation in settings reverts to english
|
|
||||||
"""
|
|
||||||
# GIVEN: gibberish notation in the settings
|
|
||||||
self.setting.setValue('songs/chord notation', 'gibberish')
|
|
||||||
# WHEN: Load is invoked
|
|
||||||
self.form.load()
|
|
||||||
# THEN: The english radio button should be checked
|
|
||||||
assert self.form.english_notation_radio_button.isChecked() is True
|
|
||||||
|
|
||||||
def test_save_check_box_settings(self):
|
def test_save_check_box_settings(form):
|
||||||
"""
|
"""
|
||||||
Test check box options are correctly saved
|
Test check box options are correctly saved
|
||||||
"""
|
"""
|
||||||
# GIVEN: A arrangement of enabled/disabled check boxes
|
# GIVEN: A arrangement of enabled/disabled check boxes
|
||||||
self.form.on_search_as_type_check_box_changed(QtCore.Qt.Unchecked)
|
form.on_search_as_type_check_box_changed(QtCore.Qt.Unchecked)
|
||||||
self.form.on_tool_bar_active_check_box_changed(QtCore.Qt.Checked)
|
form.on_tool_bar_active_check_box_changed(QtCore.Qt.Checked)
|
||||||
self.form.on_update_on_edit_check_box_changed(QtCore.Qt.Unchecked)
|
form.on_update_on_edit_check_box_changed(QtCore.Qt.Unchecked)
|
||||||
self.form.on_add_from_service_check_box_changed(QtCore.Qt.Checked)
|
form.on_add_from_service_check_box_changed(QtCore.Qt.Checked)
|
||||||
self.form.on_songbook_slide_check_box_changed(QtCore.Qt.Unchecked)
|
form.on_songbook_slide_check_box_changed(QtCore.Qt.Unchecked)
|
||||||
self.form.on_mainview_chords_check_box_changed(QtCore.Qt.Checked)
|
form.on_mainview_chords_check_box_changed(QtCore.Qt.Checked)
|
||||||
self.form.on_disable_chords_import_check_box_changed(QtCore.Qt.Unchecked)
|
form.on_disable_chords_import_check_box_changed(QtCore.Qt.Unchecked)
|
||||||
# WHEN: Save is invoked
|
# WHEN: Save is invoked
|
||||||
self.form.save()
|
form.save()
|
||||||
# THEN: The correct values should be stored in the settings
|
# THEN: The correct values should be stored in the settings
|
||||||
# song_search is currently unused
|
# song_search is currently unused
|
||||||
assert self.setting.value('songs/display songbar') is True
|
assert form.settings.value('songs/display songbar') is True
|
||||||
assert self.setting.value('songs/update service on edit') is False
|
assert form.settings.value('songs/update service on edit') is False
|
||||||
assert self.setting.value('songs/add song from service') is True
|
assert form.settings.value('songs/add song from service') is True
|
||||||
assert self.setting.value('songs/add songbook slide') is False
|
assert form.settings.value('songs/add songbook slide') is False
|
||||||
assert self.setting.value('songs/mainview chords') is True
|
assert form.settings.value('songs/mainview chords') is True
|
||||||
assert self.setting.value('songs/disable chords import') is False
|
assert form.settings.value('songs/disable chords import') is False
|
||||||
|
|
||||||
def test_english_notation_button(self):
|
|
||||||
"""
|
|
||||||
Test notation button clicked handler
|
|
||||||
"""
|
|
||||||
# GIVEN: A normal song form
|
|
||||||
# WHEN: english notation clicked
|
|
||||||
self.form.on_english_notation_button_clicked()
|
|
||||||
# THEN: Chord notation should be correct
|
|
||||||
assert self.form.chord_notation == 'english'
|
|
||||||
|
|
||||||
def test_german_notation_button(self):
|
def test_english_notation_button(form):
|
||||||
"""
|
"""
|
||||||
Test notation button clicked handler
|
Test notation button clicked handler
|
||||||
"""
|
"""
|
||||||
# GIVEN: A normal song form
|
# GIVEN: A normal song form
|
||||||
# WHEN: german notation clicked
|
# WHEN: english notation clicked
|
||||||
self.form.on_german_notation_button_clicked()
|
form.on_english_notation_button_clicked()
|
||||||
# THEN: Chord notation should be correct
|
# THEN: Chord notation should be correct
|
||||||
assert self.form.chord_notation == 'german'
|
assert form.chord_notation == 'english'
|
||||||
|
|
||||||
def test_neolatin_notation_button(self):
|
|
||||||
"""
|
|
||||||
Test notation button clicked handler
|
|
||||||
"""
|
|
||||||
# GIVEN: A normal song form
|
|
||||||
# WHEN: neolatin notation clicked
|
|
||||||
self.form.on_neolatin_notation_button_clicked()
|
|
||||||
# THEN: Chord notation should be correct
|
|
||||||
assert self.form.chord_notation == 'neo-latin'
|
|
||||||
|
|
||||||
@patch('openlp.core.common.settings.Settings.setValue')
|
def test_german_notation_button(form):
|
||||||
def test_footer_nochange(self, mocked_settings_set_val):
|
"""
|
||||||
"""
|
Test notation button clicked handler
|
||||||
Test the footer is not saved when not changed
|
"""
|
||||||
"""
|
# GIVEN: A normal song form
|
||||||
# GIVEN: A normal song form
|
# WHEN: german notation clicked
|
||||||
# WHEN: save is invoked
|
form.on_german_notation_button_clicked()
|
||||||
self.form.save()
|
# THEN: Chord notation should be correct
|
||||||
# THEN: footer should not have been saved (one less call than the change test below)
|
assert form.chord_notation == 'german'
|
||||||
assert mocked_settings_set_val.call_count == 8
|
|
||||||
|
|
||||||
@patch('openlp.core.common.settings.Settings.setValue')
|
|
||||||
def test_footer_change(self, mocked_settings_set_val):
|
|
||||||
"""
|
|
||||||
Test the footer is saved when changed
|
|
||||||
"""
|
|
||||||
# GIVEN: Footer has changed
|
|
||||||
self.form.footer_edit_box.setPlainText('A new footer')
|
|
||||||
# WHEN: save is invoked
|
|
||||||
self.form.save()
|
|
||||||
# THEN: footer should have been saved (one more call to setValue than the nochange test)
|
|
||||||
assert mocked_settings_set_val.call_count == 9
|
|
||||||
assert self.form.footer_edit_box.toPlainText() == 'A new footer'
|
|
||||||
|
|
||||||
def test_footer_reset(self):
|
def test_neolatin_notation_button(form):
|
||||||
"""
|
"""
|
||||||
Test the footer is reset when reset clicked
|
Test notation button clicked handler
|
||||||
"""
|
"""
|
||||||
# GIVEN: A default footer and different content in the edit box
|
# GIVEN: A normal song form
|
||||||
self.setting.setValue('songs/footer template', 'hello')
|
# WHEN: neolatin notation clicked
|
||||||
self.form.footer_edit_box.setPlainText('A different footer')
|
form.on_neolatin_notation_button_clicked()
|
||||||
# WHEN: reset is invoked
|
# THEN: Chord notation should be correct
|
||||||
self.form.on_footer_reset_button_clicked()
|
assert form.chord_notation == 'neo-latin'
|
||||||
# THEN: footer edit box should have been reset to the settings value
|
|
||||||
assert self.form.footer_edit_box.toPlainText() == self.setting.get_default_value('songs/footer template')
|
|
||||||
|
|
||||||
def test_save_tab_nochange(self):
|
|
||||||
"""
|
|
||||||
Test no changes does not trigger post processing
|
|
||||||
"""
|
|
||||||
# GIVEN: No changes on the form.
|
|
||||||
self.initial_color = '#999999'
|
|
||||||
# WHEN: the save is invoked
|
|
||||||
self.form.save()
|
|
||||||
# THEN: the post process should not be requested
|
|
||||||
assert 0 == self.form.settings_form.register_post_process.call_count, \
|
|
||||||
'Songs Post processing should not have been requested'
|
|
||||||
|
|
||||||
def test_save_tab_change(self):
|
@patch('openlp.core.common.settings.Settings.setValue')
|
||||||
"""
|
def test_footer_nochange(mocked_settings_set_val, form):
|
||||||
Test save after visiting the page triggers post processing.
|
"""
|
||||||
"""
|
Test the footer is not saved when not changed
|
||||||
# GIVEN: Form has been visited.
|
"""
|
||||||
self.form.tab_visited = True
|
# GIVEN: A normal song form
|
||||||
# WHEN: the save is invoked
|
# WHEN: save is invoked
|
||||||
self.form.save()
|
form.save()
|
||||||
# THEN: the post process should be requested
|
# THEN: footer should not have been saved (one less call than the change test below)
|
||||||
assert 1 == self.form.settings_form.register_post_process.call_count, \
|
assert mocked_settings_set_val.call_count == 8
|
||||||
'Songs Post processing should have been requested'
|
|
||||||
|
|
||||||
|
@patch('openlp.core.common.settings.Settings.setValue')
|
||||||
|
def test_footer_change(mocked_settings_set_val, form):
|
||||||
|
"""
|
||||||
|
Test the footer is saved when changed
|
||||||
|
"""
|
||||||
|
# GIVEN: Footer has changed
|
||||||
|
form.footer_edit_box.setPlainText('A new footer')
|
||||||
|
# WHEN: save is invoked
|
||||||
|
form.save()
|
||||||
|
# THEN: footer should have been saved (one more call to setValue than the nochange test)
|
||||||
|
assert mocked_settings_set_val.call_count == 9
|
||||||
|
assert form.footer_edit_box.toPlainText() == 'A new footer'
|
||||||
|
|
||||||
|
|
||||||
|
def test_footer_reset(form):
|
||||||
|
"""
|
||||||
|
Test the footer is reset when reset clicked
|
||||||
|
"""
|
||||||
|
# GIVEN: A default footer and different content in the edit box
|
||||||
|
form.settings.setValue('songs/footer template', 'hello')
|
||||||
|
form.footer_edit_box.setPlainText('A different footer')
|
||||||
|
# WHEN: reset is invoked
|
||||||
|
form.on_footer_reset_button_clicked()
|
||||||
|
# THEN: footer edit box should have been reset to the settings value
|
||||||
|
assert form.footer_edit_box.toPlainText() == form.settings.get_default_value('songs/footer template')
|
||||||
|
|
||||||
|
|
||||||
|
def test_save_tab_nochange(form):
|
||||||
|
"""
|
||||||
|
Test no changes does not trigger post processing
|
||||||
|
"""
|
||||||
|
# GIVEN: No changes on the form.
|
||||||
|
# WHEN: the save is invoked
|
||||||
|
form.save()
|
||||||
|
# THEN: the post process should not be requested
|
||||||
|
assert 0 == form.settings_form.register_post_process.call_count, \
|
||||||
|
'Songs Post processing should not have been requested'
|
||||||
|
|
||||||
|
|
||||||
|
def test_save_tab_change(form):
|
||||||
|
"""
|
||||||
|
Test save after visiting the page triggers post processing.
|
||||||
|
"""
|
||||||
|
# GIVEN: Form has been visited.
|
||||||
|
form.tab_visited = True
|
||||||
|
# WHEN: the save is invoked
|
||||||
|
form.save()
|
||||||
|
# THEN: the post process should be requested
|
||||||
|
assert 1 == form.settings_form.register_post_process.call_count, \
|
||||||
|
'Songs Post processing should have been requested'
|
||||||
|
@ -21,59 +21,48 @@
|
|||||||
"""
|
"""
|
||||||
Functional tests to test the AppLocation class and related methods.
|
Functional tests to test the AppLocation class and related methods.
|
||||||
"""
|
"""
|
||||||
from unittest import TestCase
|
|
||||||
|
|
||||||
from openlp.core.common import is_not_image_file
|
from openlp.core.common import is_not_image_file
|
||||||
from tests.utils.constants import RESOURCE_PATH
|
from tests.utils.constants import RESOURCE_PATH
|
||||||
from tests.helpers.testmixin import TestMixin
|
|
||||||
|
|
||||||
|
|
||||||
class TestUtils(TestCase, TestMixin):
|
def test_is_not_image_empty():
|
||||||
"""
|
"""
|
||||||
A test suite to test out various methods around the Utils functions.
|
Test the method handles an empty string
|
||||||
"""
|
"""
|
||||||
|
# Given and empty string
|
||||||
|
file_name = ""
|
||||||
|
|
||||||
def setUp(self):
|
# WHEN testing for it
|
||||||
"""
|
result = is_not_image_file(file_name)
|
||||||
Some pre-test setup required.
|
|
||||||
"""
|
|
||||||
self.setup_application()
|
|
||||||
|
|
||||||
def test_is_not_image_empty(self):
|
# THEN the result is false
|
||||||
"""
|
assert result is True, 'The missing file test should return True'
|
||||||
Test the method handles an empty string
|
|
||||||
"""
|
|
||||||
# Given and empty string
|
|
||||||
file_name = ""
|
|
||||||
|
|
||||||
# WHEN testing for it
|
|
||||||
result = is_not_image_file(file_name)
|
|
||||||
|
|
||||||
# THEN the result is false
|
def test_is_not_image_with_image_file():
|
||||||
assert result is True, 'The missing file test should return True'
|
"""
|
||||||
|
Test the method handles an image file
|
||||||
|
"""
|
||||||
|
# Given and empty string
|
||||||
|
file_path = RESOURCE_PATH / 'church.jpg'
|
||||||
|
|
||||||
def test_is_not_image_with_image_file(self):
|
# WHEN testing for it
|
||||||
"""
|
result = is_not_image_file(file_path)
|
||||||
Test the method handles an image file
|
|
||||||
"""
|
|
||||||
# Given and empty string
|
|
||||||
file_path = RESOURCE_PATH / 'church.jpg'
|
|
||||||
|
|
||||||
# WHEN testing for it
|
# THEN the result is false
|
||||||
result = is_not_image_file(file_path)
|
assert result is False, 'The file is present so the test should return False'
|
||||||
|
|
||||||
# THEN the result is false
|
|
||||||
assert result is False, 'The file is present so the test should return False'
|
|
||||||
|
|
||||||
def test_is_not_image_with_none_image_file(self):
|
def test_is_not_image_with_none_image_file():
|
||||||
"""
|
"""
|
||||||
Test the method handles a non image file
|
Test the method handles a non image file
|
||||||
"""
|
"""
|
||||||
# Given and empty string
|
# Given and empty string
|
||||||
file_path = RESOURCE_PATH / 'serviceitem_custom_1.osj'
|
file_path = RESOURCE_PATH / 'serviceitem_custom_1.osj'
|
||||||
|
|
||||||
# WHEN testing for it
|
# WHEN testing for it
|
||||||
result = is_not_image_file(file_path)
|
result = is_not_image_file(file_path)
|
||||||
|
|
||||||
# THEN the result is false
|
# THEN the result is false
|
||||||
assert result is True, 'The file is not an image file so the test should return True'
|
assert result is True, 'The file is not an image file so the test should return True'
|
||||||
|
@ -21,85 +21,72 @@
|
|||||||
"""
|
"""
|
||||||
Package to test the openlp.core.ui package.
|
Package to test the openlp.core.ui package.
|
||||||
"""
|
"""
|
||||||
from unittest import TestCase
|
import pytest
|
||||||
from unittest.mock import MagicMock, patch
|
from unittest.mock import MagicMock, patch
|
||||||
|
|
||||||
from PyQt5 import QtTest, QtWidgets
|
from PyQt5 import QtTest
|
||||||
|
|
||||||
from openlp.core.common.registry import Registry
|
|
||||||
from openlp.core.ui.filerenameform import FileRenameForm
|
from openlp.core.ui.filerenameform import FileRenameForm
|
||||||
from tests.helpers.testmixin import TestMixin
|
|
||||||
|
|
||||||
|
|
||||||
class TestStartFileRenameForm(TestCase, TestMixin):
|
@pytest.fixture()
|
||||||
|
def form(settings):
|
||||||
|
frm = FileRenameForm()
|
||||||
|
return frm
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
"""
|
|
||||||
Create the UI
|
|
||||||
"""
|
|
||||||
Registry.create()
|
|
||||||
self.setup_application()
|
|
||||||
self.main_window = QtWidgets.QMainWindow()
|
|
||||||
Registry().register('main_window', self.main_window)
|
|
||||||
self.form = FileRenameForm()
|
|
||||||
|
|
||||||
def tearDown(self):
|
def test_window_title(form):
|
||||||
"""
|
"""
|
||||||
Delete all the C++ objects at the end so that we don't have a segfault
|
Test the windowTitle of the FileRenameDialog
|
||||||
"""
|
"""
|
||||||
del self.form
|
# GIVEN: A mocked QDialog.exec() method
|
||||||
del self.main_window
|
with patch('PyQt5.QtWidgets.QDialog.exec'):
|
||||||
|
|
||||||
def test_window_title(self):
|
# WHEN: The form is executed with no args
|
||||||
"""
|
form.exec()
|
||||||
Test the windowTitle of the FileRenameDialog
|
|
||||||
"""
|
|
||||||
# GIVEN: A mocked QDialog.exec() method
|
|
||||||
with patch('PyQt5.QtWidgets.QDialog.exec'):
|
|
||||||
|
|
||||||
# WHEN: The form is executed with no args
|
# THEN: the window title is set correctly
|
||||||
self.form.exec()
|
assert form.windowTitle() == 'File Rename', 'The window title should be "File Rename"'
|
||||||
|
|
||||||
# THEN: the window title is set correctly
|
# WHEN: The form is executed with False arg
|
||||||
assert self.form.windowTitle() == 'File Rename', 'The window title should be "File Rename"'
|
form.exec(False)
|
||||||
|
|
||||||
# WHEN: The form is executed with False arg
|
# THEN: the window title is set correctly
|
||||||
self.form.exec(False)
|
assert form.windowTitle() == 'File Rename', 'The window title should be "File Rename"'
|
||||||
|
|
||||||
# THEN: the window title is set correctly
|
# WHEN: The form is executed with True arg
|
||||||
assert self.form.windowTitle() == 'File Rename', 'The window title should be "File Rename"'
|
form.exec(True)
|
||||||
|
|
||||||
# WHEN: The form is executed with True arg
|
# THEN: the window title is set correctly
|
||||||
self.form.exec(True)
|
assert form.windowTitle() == 'File Copy', 'The window title should be "File Copy"'
|
||||||
|
|
||||||
# THEN: the window title is set correctly
|
|
||||||
assert self.form.windowTitle() == 'File Copy', 'The window title should be "File Copy"'
|
|
||||||
|
|
||||||
def test_line_edit_focus(self):
|
def test_line_edit_focus(form):
|
||||||
"""
|
"""
|
||||||
Regression test for bug1067251
|
Regression test for bug1067251
|
||||||
Test that the file_name_edit setFocus has called with True when executed
|
Test that the file_name_edit setFocus has called with True when executed
|
||||||
"""
|
"""
|
||||||
# GIVEN: A mocked QDialog.exec() method and mocked file_name_edit.setFocus() method.
|
# GIVEN: A mocked QDialog.exec() method and mocked file_name_edit.setFocus() method.
|
||||||
with patch('PyQt5.QtWidgets.QDialog.exec'):
|
with patch('PyQt5.QtWidgets.QDialog.exec'):
|
||||||
mocked_set_focus = MagicMock()
|
mocked_set_focus = MagicMock()
|
||||||
self.form.file_name_edit.setFocus = mocked_set_focus
|
form.file_name_edit.setFocus = mocked_set_focus
|
||||||
|
|
||||||
# WHEN: The form is executed
|
# WHEN: The form is executed
|
||||||
self.form.exec()
|
form.exec()
|
||||||
|
|
||||||
# THEN: the setFocus method of the file_name_edit has been called with True
|
# THEN: the setFocus method of the file_name_edit has been called with True
|
||||||
mocked_set_focus.assert_called_with()
|
mocked_set_focus.assert_called_with()
|
||||||
|
|
||||||
def test_file_name_validation(self):
|
|
||||||
"""
|
|
||||||
Test the file_name_edit validation
|
|
||||||
"""
|
|
||||||
# GIVEN: QLineEdit with a validator set with illegal file name characters.
|
|
||||||
|
|
||||||
# WHEN: 'Typing' a string containing invalid file characters.
|
def test_file_name_validation(form):
|
||||||
QtTest.QTest.keyClicks(self.form.file_name_edit, r'I/n\\v?a*l|i<d> \F[i\l]e" :N+a%me')
|
"""
|
||||||
|
Test the file_name_edit validation
|
||||||
|
"""
|
||||||
|
# GIVEN: QLineEdit with a validator set with illegal file name characters.
|
||||||
|
|
||||||
# THEN: The text in the QLineEdit should be the same as the input string with the invalid characters filtered
|
# WHEN: 'Typing' a string containing invalid file characters.
|
||||||
# out.
|
QtTest.QTest.keyClicks(form.file_name_edit, r'I/n\\v?a*l|i<d> \F[i\l]e" :N+a%me')
|
||||||
assert self.form.file_name_edit.text() == 'Invalid File Name'
|
|
||||||
|
# THEN: The text in the QLineEdit should be the same as the input string with the invalid characters filtered
|
||||||
|
# out.
|
||||||
|
assert form.file_name_edit.text() == 'Invalid File Name'
|
||||||
|
@ -21,67 +21,64 @@
|
|||||||
"""
|
"""
|
||||||
Package to test the openlp.core.ui.firsttimeform package.
|
Package to test the openlp.core.ui.firsttimeform package.
|
||||||
"""
|
"""
|
||||||
|
import pytest
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from unittest import TestCase
|
|
||||||
from unittest.mock import MagicMock, call, patch
|
from unittest.mock import MagicMock, call, patch
|
||||||
|
|
||||||
from openlp.core.common.registry import Registry
|
from openlp.core.common.registry import Registry
|
||||||
from openlp.core.ui.firsttimeform import ThemeListWidgetItem
|
from openlp.core.ui.firsttimeform import ThemeListWidgetItem
|
||||||
from openlp.core.ui.icons import UiIcons
|
from openlp.core.ui.icons import UiIcons
|
||||||
from tests.helpers.testmixin import TestMixin
|
|
||||||
|
sample_theme_data = {'file_name': 'BlueBurst.otz', 'sha256': 'sha_256_hash',
|
||||||
|
'thumbnail': 'BlueBurst.png', 'title': 'Blue Burst'}
|
||||||
|
|
||||||
|
|
||||||
class TestThemeListWidgetItem(TestCase, TestMixin):
|
@pytest.yield_fixture()
|
||||||
def setUp(self):
|
def mocked_set_icon(mock_settings):
|
||||||
self.sample_theme_data = {'file_name': 'BlueBurst.otz', 'sha256': 'sha_256_hash',
|
move_to_thread_patcher = patch('openlp.core.ui.firsttimeform.DownloadWorker.moveToThread').start()
|
||||||
'thumbnail': 'BlueBurst.png', 'title': 'Blue Burst'}
|
set_icon_patcher = patch('openlp.core.ui.firsttimeform.ThemeListWidgetItem.setIcon').start()
|
||||||
Registry.create()
|
q_thread_patcher = patch('openlp.core.ui.firsttimeform.QtCore.QThread').start()
|
||||||
self.registry = Registry()
|
mocked_app = MagicMock()
|
||||||
mocked_app = MagicMock()
|
mocked_app.worker_threads = {}
|
||||||
mocked_app.worker_threads = {}
|
Registry().remove('application')
|
||||||
Registry().register('application', mocked_app)
|
Registry().register('application', mocked_app)
|
||||||
self.setup_application()
|
yield set_icon_patcher
|
||||||
|
move_to_thread_patcher.stop()
|
||||||
|
set_icon_patcher.stop()
|
||||||
|
q_thread_patcher.stop()
|
||||||
|
|
||||||
move_to_thread_patcher = patch('openlp.core.ui.firsttimeform.DownloadWorker.moveToThread')
|
|
||||||
self.addCleanup(move_to_thread_patcher.stop)
|
|
||||||
move_to_thread_patcher.start()
|
|
||||||
set_icon_patcher = patch('openlp.core.ui.firsttimeform.ThemeListWidgetItem.setIcon')
|
|
||||||
self.addCleanup(set_icon_patcher.stop)
|
|
||||||
self.mocked_set_icon = set_icon_patcher.start()
|
|
||||||
q_thread_patcher = patch('openlp.core.ui.firsttimeform.QtCore.QThread')
|
|
||||||
self.addCleanup(q_thread_patcher.stop)
|
|
||||||
q_thread_patcher.start()
|
|
||||||
|
|
||||||
def test_failed_download(self):
|
def test_failed_download(mocked_set_icon):
|
||||||
"""
|
"""
|
||||||
Test that icon get set to indicate a failure when `DownloadWorker` emits the download_failed signal
|
Test that icon get set to indicate a failure when `DownloadWorker` emits the download_failed signal
|
||||||
"""
|
"""
|
||||||
# GIVEN: An instance of `DownloadWorker`
|
# GIVEN: An instance of `DownloadWorker`
|
||||||
instance = ThemeListWidgetItem('url', self.sample_theme_data, MagicMock()) # noqa Overcome GC issue
|
instance = ThemeListWidgetItem('url', sample_theme_data, MagicMock()) # noqa Overcome GC issue
|
||||||
worker_threads = Registry().get('application').worker_threads
|
worker_threads = Registry().get('application').worker_threads
|
||||||
worker = worker_threads['thumbnail_download_BlueBurst.png']['worker']
|
worker = worker_threads['thumbnail_download_BlueBurst.png']['worker']
|
||||||
|
|
||||||
# WHEN: `DownloadWorker` emits the `download_failed` signal
|
# WHEN: `DownloadWorker` emits the `download_failed` signal
|
||||||
worker.download_failed.emit()
|
worker.download_failed.emit()
|
||||||
|
|
||||||
# THEN: Then the initial loading icon should have been replaced by the exception icon
|
# THEN: Then the initial loading icon should have been replaced by the exception icon
|
||||||
self.mocked_set_icon.assert_has_calls([call(UiIcons().picture), call(UiIcons().exception)])
|
mocked_set_icon.assert_has_calls([call(UiIcons().picture), call(UiIcons().exception)])
|
||||||
|
|
||||||
@patch('openlp.core.ui.firsttimeform.build_icon')
|
|
||||||
def test_successful_download(self, mocked_build_icon):
|
|
||||||
"""
|
|
||||||
Test that the downloaded thumbnail is set as the icon when `DownloadWorker` emits the `download_succeeded`
|
|
||||||
signal
|
|
||||||
"""
|
|
||||||
# GIVEN: An instance of `DownloadWorker`
|
|
||||||
instance = ThemeListWidgetItem('url', self.sample_theme_data, MagicMock()) # noqa Overcome GC issue
|
|
||||||
worker_threads = Registry().get('application').worker_threads
|
|
||||||
worker = worker_threads['thumbnail_download_BlueBurst.png']['worker']
|
|
||||||
test_path = Path('downlaoded', 'file')
|
|
||||||
|
|
||||||
# WHEN: `DownloadWorker` emits the `download_succeeded` signal
|
@patch('openlp.core.ui.firsttimeform.build_icon')
|
||||||
worker.download_succeeded.emit(test_path)
|
def test_successful_download(mocked_build_icon, mocked_set_icon):
|
||||||
|
"""
|
||||||
|
Test that the downloaded thumbnail is set as the icon when `DownloadWorker` emits the `download_succeeded`
|
||||||
|
signal
|
||||||
|
"""
|
||||||
|
# GIVEN: An instance of `DownloadWorker`
|
||||||
|
instance = ThemeListWidgetItem('url', sample_theme_data, MagicMock()) # noqa Overcome GC issue
|
||||||
|
worker_threads = Registry().get('application').worker_threads
|
||||||
|
worker = worker_threads['thumbnail_download_BlueBurst.png']['worker']
|
||||||
|
test_path = Path('downlaoded', 'file')
|
||||||
|
|
||||||
# THEN: An icon should have been built from the downloaded file and used to replace the loading icon
|
# WHEN: `DownloadWorker` emits the `download_succeeded` signal
|
||||||
mocked_build_icon.assert_called_once_with(test_path)
|
worker.download_succeeded.emit(test_path)
|
||||||
self.mocked_set_icon.assert_has_calls([call(UiIcons().picture), call(mocked_build_icon())])
|
|
||||||
|
# THEN: An icon should have been built from the downloaded file and used to replace the loading icon
|
||||||
|
mocked_build_icon.assert_called_once_with(test_path)
|
||||||
|
mocked_set_icon.assert_has_calls([call(UiIcons().picture), call(mocked_build_icon())])
|
||||||
|
@ -21,101 +21,81 @@
|
|||||||
"""
|
"""
|
||||||
Package to test the openlp.core.ui.mainwindow package.
|
Package to test the openlp.core.ui.mainwindow package.
|
||||||
"""
|
"""
|
||||||
from unittest import TestCase, skipIf, skip
|
import pytest
|
||||||
from unittest.mock import MagicMock, patch
|
from unittest.mock import MagicMock, patch
|
||||||
|
|
||||||
from PyQt5 import QtGui
|
from PyQt5 import QtGui
|
||||||
|
|
||||||
from openlp.core.state import State
|
from openlp.core.state import State
|
||||||
from openlp.core.common import is_macosx
|
|
||||||
from openlp.core.common.registry import Registry
|
from openlp.core.common.registry import Registry
|
||||||
from openlp.core.common.settings import Settings
|
|
||||||
from openlp.core.lib.plugin import PluginStatus
|
from openlp.core.lib.plugin import PluginStatus
|
||||||
from openlp.core.ui.mainwindow import MainWindow
|
from openlp.core.ui.mainwindow import MainWindow
|
||||||
from tests.helpers.testmixin import TestMixin
|
|
||||||
|
|
||||||
|
|
||||||
@skipIf(is_macosx(), 'Skip on macOS until we can figure out what the problem is or the tests are refactored')
|
@pytest.fixture()
|
||||||
class TestMainWindow(TestCase, TestMixin):
|
def main_window(settings, state):
|
||||||
|
"""
|
||||||
|
Create the UI
|
||||||
|
"""
|
||||||
|
Registry().set_flag('no_web_server', True)
|
||||||
|
mocked_plugin = MagicMock()
|
||||||
|
mocked_plugin.status = PluginStatus.Active
|
||||||
|
mocked_plugin.icon = QtGui.QIcon()
|
||||||
|
Registry().register('mock_plugin', mocked_plugin)
|
||||||
|
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
|
||||||
|
# Mock classes and methods used by mainwindow.
|
||||||
|
with patch('openlp.core.ui.mainwindow.SettingsForm'), \
|
||||||
|
patch('openlp.core.ui.mainwindow.OpenLPDockWidget'), \
|
||||||
|
patch('openlp.core.ui.mainwindow.QtWidgets.QToolBox'), \
|
||||||
|
patch('openlp.core.ui.mainwindow.QtWidgets.QMainWindow.addDockWidget'), \
|
||||||
|
patch('openlp.core.ui.mainwindow.ServiceManager'), \
|
||||||
|
patch('openlp.core.ui.mainwindow.ThemeManager'), \
|
||||||
|
patch('openlp.core.ui.mainwindow.ProjectorManager'), \
|
||||||
|
patch('openlp.core.ui.mainwindow.HttpServer'), \
|
||||||
|
patch('openlp.core.ui.mainwindow.WebSocketServer'), \
|
||||||
|
patch('openlp.core.ui.mainwindow.start_zeroconf'), \
|
||||||
|
patch('openlp.core.ui.mainwindow.PluginForm'):
|
||||||
|
return MainWindow()
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
"""
|
|
||||||
Create the UI
|
|
||||||
"""
|
|
||||||
Registry.create()
|
|
||||||
self.registry = Registry()
|
|
||||||
self.setup_application()
|
|
||||||
# Mock cursor busy/normal methods.
|
|
||||||
self.app.set_busy_cursor = MagicMock()
|
|
||||||
self.app.set_normal_cursor = MagicMock()
|
|
||||||
self.app.args = []
|
|
||||||
Registry().register('application', self.app)
|
|
||||||
Registry().register('settings', Settings())
|
|
||||||
Registry().set_flag('no_web_server', True)
|
|
||||||
mocked_plugin = MagicMock()
|
|
||||||
mocked_plugin.status = PluginStatus.Active
|
|
||||||
mocked_plugin.icon = QtGui.QIcon()
|
|
||||||
Registry().register('mock_plugin', mocked_plugin)
|
|
||||||
State().load_settings()
|
|
||||||
State().add_service("mock", 1, is_plugin=True, status=PluginStatus.Active)
|
|
||||||
# Mock classes and methods used by mainwindow.
|
|
||||||
with patch('openlp.core.ui.mainwindow.SettingsForm'), \
|
|
||||||
patch('openlp.core.ui.mainwindow.OpenLPDockWidget'), \
|
|
||||||
patch('openlp.core.ui.mainwindow.QtWidgets.QToolBox'), \
|
|
||||||
patch('openlp.core.ui.mainwindow.QtWidgets.QMainWindow.addDockWidget'), \
|
|
||||||
patch('openlp.core.ui.mainwindow.ServiceManager'), \
|
|
||||||
patch('openlp.core.ui.mainwindow.ThemeManager'), \
|
|
||||||
patch('openlp.core.ui.mainwindow.ProjectorManager'), \
|
|
||||||
patch('openlp.core.ui.mainwindow.HttpServer'), \
|
|
||||||
patch('openlp.core.ui.mainwindow.WebSocketServer'), \
|
|
||||||
patch('openlp.core.ui.mainwindow.start_zeroconf'), \
|
|
||||||
patch('openlp.core.ui.mainwindow.PluginForm'):
|
|
||||||
self.main_window = MainWindow()
|
|
||||||
|
|
||||||
def tearDown(self):
|
def test_restore_current_media_manager_item(main_window):
|
||||||
"""
|
"""
|
||||||
Delete all the C++ objects at the end so that we don't have a segfault
|
Regression test for bug #1152509.
|
||||||
"""
|
"""
|
||||||
del self.main_window
|
# save current plugin: True; current media plugin: 2
|
||||||
|
main_window.settings.setValue('advanced/save current plugin', True)
|
||||||
|
main_window.settings.setValue('advanced/current media plugin', 2)
|
||||||
|
|
||||||
@skip('Fix when migrate to PyTest')
|
# WHEN: Call the restore method.
|
||||||
def test_restore_current_media_manager_item(self):
|
main_window.restore_current_media_manager_item()
|
||||||
"""
|
|
||||||
Regression test for bug #1152509.
|
|
||||||
"""
|
|
||||||
# GIVEN: Mocked Settings().value method.
|
|
||||||
with patch('openlp.core.ui.mainwindow.Settings.value') as mocked_value:
|
|
||||||
# save current plugin: True; current media plugin: 2
|
|
||||||
mocked_value.side_effect = [True, 2]
|
|
||||||
|
|
||||||
# WHEN: Call the restore method.
|
# THEN: The current widget should have been set.
|
||||||
self.main_window.restore_current_media_manager_item()
|
main_window.media_tool_box.setCurrentIndex.assert_called_with(2)
|
||||||
|
|
||||||
# THEN: The current widget should have been set.
|
|
||||||
self.main_window.media_tool_box.setCurrentIndex.assert_called_with(2)
|
|
||||||
|
|
||||||
def test_projector_manager_dock_locked(self):
|
def test_projector_manager_dock_locked(main_window):
|
||||||
"""
|
"""
|
||||||
Projector Manager enable UI options - bug #1390702
|
Projector Manager enable UI options - bug #1390702
|
||||||
"""
|
"""
|
||||||
# GIVEN: A mocked projector manager dock item:
|
# GIVEN: A mocked projector manager dock item:
|
||||||
projector_dock = self.main_window.projector_manager_dock
|
projector_dock = main_window.projector_manager_dock
|
||||||
|
|
||||||
# WHEN: main_window.lock_panel action is triggered
|
# WHEN: main_window.lock_panel action is triggered
|
||||||
self.main_window.lock_panel.triggered.emit(True)
|
main_window.lock_panel.triggered.emit(True)
|
||||||
|
|
||||||
# THEN: Projector manager dock should have been called with disable UI features
|
# THEN: Projector manager dock should have been called with disable UI features
|
||||||
projector_dock.setFeatures.assert_called_with(0)
|
projector_dock.setFeatures.assert_called_with(0)
|
||||||
|
|
||||||
def test_projector_manager_dock_unlocked(self):
|
|
||||||
"""
|
|
||||||
Projector Manager disable UI options - bug #1390702
|
|
||||||
"""
|
|
||||||
# GIVEN: A mocked projector manager dock item:
|
|
||||||
projector_dock = self.main_window.projector_manager_dock
|
|
||||||
|
|
||||||
# WHEN: main_window.lock_panel action is triggered
|
def test_projector_manager_dock_unlocked(main_window):
|
||||||
self.main_window.lock_panel.triggered.emit(False)
|
"""
|
||||||
|
Projector Manager disable UI options - bug #1390702
|
||||||
|
"""
|
||||||
|
# GIVEN: A mocked projector manager dock item:
|
||||||
|
projector_dock = main_window.projector_manager_dock
|
||||||
|
|
||||||
# THEN: Projector manager dock should have been called with enable UI features
|
# WHEN: main_window.lock_panel action is triggered
|
||||||
projector_dock.setFeatures.assert_called_with(7)
|
main_window.lock_panel.triggered.emit(False)
|
||||||
|
|
||||||
|
# THEN: Projector manager dock should have been called with enable UI features
|
||||||
|
projector_dock.setFeatures.assert_called_with(7)
|
||||||
|
Loading…
Reference in New Issue
Block a user