# -*- coding: utf-8 -*- ########################################################################## # OpenLP - Open Source Lyrics Projection # # ---------------------------------------------------------------------- # # Copyright (c) 2008-2024 OpenLP Developers # # ---------------------------------------------------------------------- # # This program is free software: you can redistribute it and/or modify # # it under the terms of the GNU General Public License as published by # # the Free Software Foundation, either version 3 of the License, or # # (at your option) any later version. # # # # This program is distributed in the hope that it will be useful, # # but WITHOUT ANY WARRANTY; without even the implied warranty of # # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # # GNU General Public License for more details. # # # # You should have received a copy of the GNU General Public License # # along with this program. If not, see . # ########################################################################## """ This module contains tests for the lib submodule of the Songs plugin. """ import logging import pytest from unittest.mock import MagicMock, patch from PyQt5 import QtCore, QtWidgets from openlp.core.common.registry import Registry from openlp.core.common.settings import Settings from openlp.plugins.songs.forms.editsongform import EditSongForm from openlp.plugins.songs.lib import VerseType from openlp.plugins.songs.lib.db import Author @pytest.fixture() def edit_song_form(): with patch('openlp.plugins.songs.forms.editsongform.EditSongForm.__init__', return_value=None): return EditSongForm(None, MagicMock(), MagicMock()) @pytest.fixture() def edit_song_form_with_ui(settings: Settings) -> EditSongForm: main_window = QtWidgets.QMainWindow() Registry().register('main_window', main_window) Registry().register('theme_manager', MagicMock()) form = EditSongForm(None, main_window, MagicMock()) yield form del form del main_window def test_validate_matching_tags(edit_song_form): # Given a set of tags tags = ['{r}', '{/r}', '{bl}', '{/bl}', '{su}', '{/su}'] # WHEN we validate them valid = edit_song_form._validate_tags(tags) # THEN they should be valid assert valid is True, "The tags list should be valid" def test_validate_nonmatching_tags(edit_song_form): # Given a set of tags tags = ['{r}', '{/r}', '{bl}', '{/bl}', '{br}', '{su}', '{/su}'] # WHEN we validate them valid = edit_song_form._validate_tags(tags) # THEN they should be valid assert valid is True, "The tags list should be valid" @patch('openlp.plugins.songs.forms.editsongform.set_case_insensitive_completer') def test_load_objects(mocked_set_case_insensitive_completer, edit_song_form, settings): """ Test the _load_objects() method """ # GIVEN: A song edit form and some mocked stuff mocked_class = MagicMock() mocked_class.name = 'Author' mocked_combo = MagicMock() mocked_combo.count.return_value = 0 mocked_cache = MagicMock() mocked_object = MagicMock() mocked_object.name = 'Charles' mocked_object.id = 1 mocked_manager = MagicMock() mocked_manager.get_all_objects.return_value = [mocked_object] edit_song_form.manager = mocked_manager # WHEN: _load_objects() is called edit_song_form._load_objects(mocked_class, mocked_combo, mocked_cache) # THEN: All the correct methods should have been called edit_song_form.manager.get_all_objects.assert_called_once_with(mocked_class) mocked_combo.clear.assert_called_once_with() mocked_combo.count.assert_called_once_with() mocked_combo.addItem.assert_called_once_with('Charles') mocked_cache.append.assert_called_once_with('Charles') mocked_combo.setItemData.assert_called_once_with(0, 1) mocked_set_case_insensitive_completer.assert_called_once_with(mocked_cache, mocked_combo) mocked_combo.setCurrentIndex.assert_called_once_with(-1) mocked_combo.setCurrentText.assert_called_once_with('') def test_add_multiple_audio_from_file(edit_song_form_with_ui: EditSongForm): """ Test that not more than one Linked Audio item can be added """ # GIVEN: A Linked Audio list with 1 item and mocked error message handler item = QtWidgets.QListWidgetItem('Audio file') edit_song_form_with_ui.audio_list_widget.addItem(item) mocked_error_message = MagicMock() Registry().get('main_window').error_message = mocked_error_message # WHEN: Add File is clicked edit_song_form_with_ui.on_audio_add_from_file_button_clicked() # THEN: A call to show an error message should have been made and no items should have been added mocked_error_message.assert_called_once() assert edit_song_form_with_ui.audio_list_widget.count() == 1 def test_add_multiple_audio_from_media(edit_song_form_with_ui: EditSongForm): """ Test that not more than one Linked Audio item can be added """ # GIVEN: A Linked Audio list with 1 item and mocked error message handler item = QtWidgets.QListWidgetItem('Audio file') edit_song_form_with_ui.audio_list_widget.addItem(item) mocked_error_message = MagicMock() Registry().get('main_window').error_message = mocked_error_message # WHEN: Add Media is clicked edit_song_form_with_ui.on_audio_add_from_media_button_clicked() # THEN: A call to show an error message should have been made and no items should have been added mocked_error_message.assert_called_once() assert edit_song_form_with_ui.audio_list_widget.count() == 1 def test_validate_song_multiple_audio(edit_song_form_with_ui: EditSongForm): """ Test that a form with multiple Linked Audio items does not pass validation """ # GIVEN: A form with title, lyrics, an author, and 2 Linked Audio items edit_song_form_with_ui.title_edit.setText('Song Title') verse_def = '{tag}{number}'.format(tag=VerseType.tags[0], number=1) song_lyrics = 'Song Lyrics' verse_item = QtWidgets.QTableWidgetItem(song_lyrics) verse_item.setData(QtCore.Qt.UserRole, verse_def) verse_item.setText(song_lyrics) edit_song_form_with_ui.verse_list_widget.setRowCount(1) edit_song_form_with_ui.verse_list_widget.setItem(0, 0, verse_item) item_1 = QtWidgets.QListWidgetItem('Audio file 1') item_2 = QtWidgets.QListWidgetItem('Audio file 2') edit_song_form_with_ui.audio_list_widget.addItem(item_1) edit_song_form_with_ui.audio_list_widget.addItem(item_2) author = Author(first_name='', last_name='', display_name='Author') author_type = edit_song_form_with_ui.author_types_combo_box.itemData(0) edit_song_form_with_ui._add_author_to_list(author, author_type) mocked_error_message = MagicMock() Registry().get('main_window').error_message = mocked_error_message # WHEN: Song is validated song_valid = edit_song_form_with_ui._validate_song() # THEN: It should not be valid assert song_valid is False def test_validate_song_one_audio(edit_song_form_with_ui: EditSongForm): """ Test that a form with one Linked Audio item passes validation """ # GIVEN: A form with title, lyrics, an author, and 1 Linked Audio item edit_song_form_with_ui.title_edit.setText('Song Title') verse_def = '{tag}{number}'.format(tag=VerseType.tags[0], number=1) song_lyrics = 'Song Lyrics' verse_item = QtWidgets.QTableWidgetItem(song_lyrics) verse_item.setData(QtCore.Qt.UserRole, verse_def) verse_item.setText(song_lyrics) edit_song_form_with_ui.verse_list_widget.setRowCount(1) edit_song_form_with_ui.verse_list_widget.setItem(0, 0, verse_item) item_1 = QtWidgets.QListWidgetItem('Audio file 1') edit_song_form_with_ui.audio_list_widget.addItem(item_1) author = Author(first_name='', last_name='', display_name='Author') author_type = edit_song_form_with_ui.author_types_combo_box.itemData(0) edit_song_form_with_ui._add_author_to_list(author, author_type) # If the validation does fail for some reason it will likely try to display an error message, # so make sure error_message exists to avoid an error mocked_error_message = MagicMock() Registry().get('main_window').error_message = mocked_error_message # WHEN: Song is validated song_valid = edit_song_form_with_ui._validate_song() # Log the error message to help determine the cause in the case validation failed if mocked_error_message.called: _title, message = mocked_error_message.call_args.args logging.error('Validation error message: {message}'.format(message=message)) # THEN: It should be valid assert song_valid is True