Change the filter to be SQLAlchemy 2 compatible

This commit is contained in:
Raoul Snyman 2024-01-23 21:31:43 -07:00
parent 3778448e76
commit de068a5625
4 changed files with 205 additions and 123 deletions

View File

@ -38,6 +38,9 @@ class Registry(metaclass=Singleton):
"""
log.info('Registry loaded')
# Try to get around the AttributeError in tests
functions_list = {}
@classmethod
def create(cls) -> 'Registry':
"""

View File

@ -30,7 +30,7 @@ from openlp.core.lib.ui import critical_error_message_box
from openlp.plugins.songs.forms.authorsform import AuthorsForm
from openlp.plugins.songs.forms.songbookform import SongBookForm
from openlp.plugins.songs.forms.topicsform import TopicsForm
from openlp.plugins.songs.lib.db import Author, SongBook, Song, Topic, SongBookEntry
from openlp.plugins.songs.lib.db import Author, AuthorSong, SongBook, Song, Topic, SongBookEntry
from .songmaintenancedialog import Ui_SongMaintenanceDialog
@ -431,7 +431,13 @@ class SongMaintenanceForm(QtWidgets.QDialog, Ui_SongMaintenanceDialog, RegistryP
)
)
# Find the songs, which have the old_author as author.
songs = self.manager.get_all_objects(Song, Song.authors.contains(old_author))
songs = self.manager.get_all_objects(
Song,
and_(
Song.id == AuthorSong.song_id,
AuthorSong.author_id == old_author.id
)
)
for song in songs:
for author_song in song.authors_songs:
song.add_author(existing_author, author_song.author_type)

3
pytest.ini Normal file
View File

@ -0,0 +1,3 @@
[pytest]
filterwarnings =
ignore::UserWarning

View File

@ -30,94 +30,94 @@ from PyQt5 import QtCore, QtWidgets
from openlp.core.common.i18n import UiStrings
from openlp.core.common.registry import Registry
from openlp.core.common.settings import Settings
from openlp.core.db.manager import DBManager
from openlp.plugins.songs.lib.db import init_schema, SongBook, Song, SongBookEntry
from openlp.plugins.songs.lib.db import init_schema, Author, AuthorSong, SongBook, Song, SongBookEntry
from openlp.plugins.songs.forms.songmaintenanceform import SongMaintenanceForm
from sqlalchemy.sql import and_
@pytest.fixture()
def form_env(settings):
def db_manager() -> MagicMock():
return MagicMock()
@pytest.fixture()
def maintenance_form(registry: Registry, settings: Settings, db_manager: MagicMock) -> SongMaintenanceForm:
main_window = QtWidgets.QMainWindow()
Registry().register('main_window', main_window)
mocked_manager = MagicMock()
frm = SongMaintenanceForm(mocked_manager)
yield frm, mocked_manager
registry.register('main_window', main_window)
frm = SongMaintenanceForm(db_manager)
yield frm
del frm
del main_window
def test_constructor(form_env):
def test_constructor(db_manager: MagicMock, maintenance_form: SongMaintenanceForm):
"""
Test that a SongMaintenanceForm is created successfully
"""
# GIVEN: A SongMaintenanceForm
form = form_env[0]
mocked_manager = form_env[1]
# WHEN: The form is created
# THEN: It should have some of the right components
assert form is not None
assert form.manager is mocked_manager
assert maintenance_form is not None
assert maintenance_form.manager is db_manager
@patch.object(QtWidgets.QDialog, 'exec')
def test_exect(mocked_exec, form_env):
@patch('openlp.plugins.songs.forms.songmaintenanceform.QtWidgets.QDialog.exec')
def test_exec(mocked_exec: MagicMock, maintenance_form: SongMaintenanceForm):
"""
Test the song maintenance form being executed
"""
# GIVEN: A song maintenance form
form = form_env[0]
mocked_exec.return_value = True
# WHEN: The song mainetnance form is executed
with patch.object(form, 'type_list_widget') as mocked_type_list_widget, \
patch.object(form, 'reset_authors') as mocked_reset_authors, \
patch.object(form, 'reset_topics') as mocked_reset_topics, \
patch.object(form, 'reset_song_books') as mocked_reset_song_books:
result = form.exec(from_song_edit=True)
with patch.object(maintenance_form, 'type_list_widget') as mocked_type_list_widget, \
patch.object(maintenance_form, 'reset_authors') as mocked_reset_authors, \
patch.object(maintenance_form, 'reset_topics') as mocked_reset_topics, \
patch.object(maintenance_form, 'reset_song_books') as mocked_reset_song_books:
result = maintenance_form.exec(from_song_edit=True)
# THEN: The correct methods should have been called
assert form.from_song_edit is True
assert maintenance_form.from_song_edit is True
mocked_type_list_widget.setCurrentRow.assert_called_once_with(0)
mocked_reset_authors.assert_called_once_with()
mocked_reset_topics.assert_called_once_with()
mocked_reset_song_books.assert_called_once_with()
mocked_type_list_widget.setFocus.assert_called_once_with()
mocked_exec.assert_called_once_with(form)
mocked_exec.assert_called_once_with(maintenance_form)
assert result is True
def test_get_current_item_id_no_item(form_env):
def test_get_current_item_id_no_item(maintenance_form: SongMaintenanceForm):
"""
Test _get_current_item_id() when there's no item
"""
# GIVEN: A song maintenance form without a selected item
form = form_env[0]
mocked_list_widget = MagicMock()
mocked_list_widget.currentItem.return_value = None
# WHEN: _get_current_item_id() is called
result = form._get_current_item_id(mocked_list_widget)
result = maintenance_form._get_current_item_id(mocked_list_widget)
# THEN: The result should be -1
mocked_list_widget.currentItem.assert_called_once_with()
assert result == -1
def test_get_current_item_id(form_env):
def test_get_current_item_id(maintenance_form: SongMaintenanceForm):
"""
Test _get_current_item_id() when there's a valid item
"""
# GIVEN: A song maintenance form with a selected item
form = form_env[0]
mocked_item = MagicMock()
mocked_item.data.return_value = 7
mocked_list_widget = MagicMock()
mocked_list_widget.currentItem.return_value = mocked_item
# WHEN: _get_current_item_id() is called
result = form._get_current_item_id(mocked_list_widget)
result = maintenance_form._get_current_item_id(mocked_list_widget)
# THEN: The result should be -1
mocked_list_widget.currentItem.assert_called_once_with()
@ -126,13 +126,12 @@ def test_get_current_item_id(form_env):
@patch('openlp.plugins.songs.forms.songmaintenanceform.critical_error_message_box')
def test_delete_item_no_item_id(mocked_critical_error_message_box, form_env):
def test_delete_item_no_item_id(mocked_critical_error_message_box: MagicMock, maintenance_form: SongMaintenanceForm):
"""
Test the _delete_item() method when there is no item selected
"""
# GIVEN: Some mocked items
form, manager = form_env
manager.get_object.return_value = None
maintenance_form.manager.get_object.return_value = None
mocked_list_widget = MagicMock()
mocked_reset_func = MagicMock()
dialog_title = 'Delete Item'
@ -140,10 +139,10 @@ def test_delete_item_no_item_id(mocked_critical_error_message_box, form_env):
error_text = 'There was a problem deleting this item'
# WHEN: _delete_item() is called
with patch.object(form, '_get_current_item_id') as mocked_get_current_item_id:
with patch.object(maintenance_form, '_get_current_item_id') as mocked_get_current_item_id:
mocked_get_current_item_id.return_value = -1
form._delete_item(SongBook, mocked_list_widget, mocked_reset_func, dialog_title, delete_text,
error_text)
maintenance_form._delete_item(SongBook, mocked_list_widget, mocked_reset_func, dialog_title, delete_text,
error_text)
# THEN: The right things should have been called
mocked_get_current_item_id.assert_called_once_with(mocked_list_widget)
@ -151,13 +150,12 @@ def test_delete_item_no_item_id(mocked_critical_error_message_box, form_env):
@patch('openlp.plugins.songs.forms.songmaintenanceform.critical_error_message_box')
def test_delete_item_invalid_item(mocked_critical_error_message_box, form_env):
def test_delete_item_invalid_item(mocked_critical_error_message_box: MagicMock, maintenance_form: SongMaintenanceForm):
"""
Test the _delete_item() method when the item doesn't exist in the database
"""
# GIVEN: Some mocked items
form, manager = form_env
manager.get_object.return_value = None
maintenance_form.manager.get_object.return_value = None
mocked_list_widget = MagicMock()
mocked_reset_func = MagicMock()
dialog_title = 'Delete Item'
@ -165,28 +163,27 @@ def test_delete_item_invalid_item(mocked_critical_error_message_box, form_env):
error_text = 'There was a problem deleting this item'
# WHEN: _delete_item() is called
with patch.object(form, '_get_current_item_id') as mocked_get_current_item_id:
with patch.object(maintenance_form, '_get_current_item_id') as mocked_get_current_item_id:
mocked_get_current_item_id.return_value = 1
form._delete_item(SongBook, mocked_list_widget, mocked_reset_func, dialog_title, delete_text,
error_text)
maintenance_form._delete_item(SongBook, mocked_list_widget, mocked_reset_func, dialog_title, delete_text,
error_text)
# THEN: The right things should have been called
mocked_get_current_item_id.assert_called_once_with(mocked_list_widget)
manager.get_object.assert_called_once_with(SongBook, 1)
maintenance_form.manager.get_object.assert_called_once_with(SongBook, 1)
mocked_critical_error_message_box.assert_called_once_with(dialog_title, error_text)
@patch('openlp.plugins.songs.forms.songmaintenanceform.critical_error_message_box')
def test_delete_item(mocked_critical_error_message_box, form_env):
def test_delete_item(mocked_critical_error_message_box: MagicMock, maintenance_form: SongMaintenanceForm):
"""
Test the _delete_item() method
"""
# GIVEN: Some mocked items
form, mocked_manager = form_env
mocked_item = MagicMock()
mocked_item.songs = []
mocked_item.id = 1
mocked_manager.get_object.return_value = mocked_item
maintenance_form.manager.get_object.return_value = mocked_item
mocked_critical_error_message_box.return_value = QtWidgets.QMessageBox.Yes
mocked_list_widget = MagicMock()
mocked_reset_func = MagicMock()
@ -195,30 +192,29 @@ def test_delete_item(mocked_critical_error_message_box, form_env):
error_text = 'There was a problem deleting this item'
# WHEN: _delete_item() is called
with patch.object(form, '_get_current_item_id') as mocked_get_current_item_id:
with patch.object(maintenance_form, '_get_current_item_id') as mocked_get_current_item_id:
mocked_get_current_item_id.return_value = 1
form._delete_item(SongBook, mocked_list_widget, mocked_reset_func, dialog_title, delete_text,
error_text)
maintenance_form._delete_item(SongBook, mocked_list_widget, mocked_reset_func, dialog_title, delete_text,
error_text)
# THEN: The right things should have been called
mocked_get_current_item_id.assert_called_once_with(mocked_list_widget)
mocked_manager.get_object.assert_called_once_with(SongBook, 1)
mocked_critical_error_message_box.assert_called_once_with(dialog_title, delete_text, form, True)
mocked_manager.delete_object.assert_called_once_with(SongBook, 1)
maintenance_form.manager.get_object.assert_called_once_with(SongBook, 1)
mocked_critical_error_message_box.assert_called_once_with(dialog_title, delete_text, maintenance_form, True)
maintenance_form.manager.delete_object.assert_called_once_with(SongBook, 1)
mocked_reset_func.assert_called_once_with()
@patch('openlp.plugins.songs.forms.songmaintenanceform.critical_error_message_box')
def test_delete_book_assigned(mocked_critical_error_message_box, form_env):
def test_delete_book_assigned(mocked_critical_error_message_box: MagicMock, maintenance_form: SongMaintenanceForm):
"""
Test the _delete_item() method
"""
# GIVEN: Some mocked items
form, mocked_manager = form_env
mocked_item = create_autospec(SongBook, spec_set=True)
mocked_item.id = 1
mocked_item.songs = [MagicMock(title='Amazing Grace')]
mocked_manager.get_object.return_value = mocked_item
maintenance_form.manager.get_object.return_value = mocked_item
mocked_critical_error_message_box.return_value = QtWidgets.QMessageBox.Yes
mocked_list_widget = MagicMock()
mocked_reset_func = MagicMock()
@ -227,28 +223,27 @@ def test_delete_book_assigned(mocked_critical_error_message_box, form_env):
error_text = 'This book cannot be deleted, it is currenty assigned to at least one song.'
# WHEN: _delete_item() is called
with patch.object(form, '_get_current_item_id') as mocked_get_current_item_id:
with patch.object(maintenance_form, '_get_current_item_id') as mocked_get_current_item_id:
mocked_get_current_item_id.return_value = 1
form._delete_item(SongBook, mocked_list_widget, mocked_reset_func, dialog_title, delete_text,
error_text)
maintenance_form._delete_item(SongBook, mocked_list_widget, mocked_reset_func, dialog_title, delete_text,
error_text)
# THEN: The right things should have been called
mocked_get_current_item_id.assert_called_once_with(mocked_list_widget)
mocked_manager.get_object.assert_called_once_with(SongBook, 1)
maintenance_form.manager.get_object.assert_called_once_with(SongBook, 1)
mocked_critical_error_message_box.assert_called_once_with(dialog_title, error_text + '\n\nAmazing Grace')
mocked_manager.delete_object.assert_not_called()
maintenance_form.manager.delete_object.assert_not_called()
mocked_reset_func.assert_not_called()
@patch('openlp.plugins.songs.forms.songmaintenanceform.QtWidgets.QListWidgetItem')
@patch('openlp.plugins.songs.forms.songmaintenanceform.Author')
def test_reset_authors(MockedAuthor, MockedQListWidgetItem, form_env):
def test_reset_authors(MockedAuthor: MagicMock, MockedQListWidgetItem: MagicMock,
maintenance_form: SongMaintenanceForm):
"""
Test the reset_authors() method
"""
# GIVEN: A mocked authors_list_widget and a few other mocks
form = form_env[0]
mocked_manager = form_env[1]
mocked_author1 = MagicMock()
mocked_author1.display_name = 'John Newton'
mocked_author1.id = 1
@ -262,16 +257,16 @@ def test_reset_authors(MockedAuthor, MockedQListWidgetItem, form_env):
mocked_author_item2 = MagicMock()
MockedQListWidgetItem.side_effect = [mocked_author_item1, mocked_author_item2]
MockedAuthor.display_name = None
mocked_manager.get_all_objects.return_value = mocked_authors
maintenance_form.manager.get_all_objects.return_value = mocked_authors
# WHEN: reset_authors() is called
with patch.object(form, 'authors_list_widget') as mocked_authors_list_widget:
form.reset_authors()
with patch.object(maintenance_form, 'authors_list_widget') as mocked_authors_list_widget:
maintenance_form.reset_authors()
# THEN: The authors list should be reset
expected_widget_item_calls = [call('John Wesley'), call('John Newton')]
mocked_authors_list_widget.clear.assert_called_once_with()
mocked_manager.get_all_objects.assert_called_once_with(MockedAuthor)
maintenance_form.manager.get_all_objects.assert_called_once_with(MockedAuthor)
# Do not care which order items are called since the order is different on macos vs others
MockedQListWidgetItem.assert_has_calls(expected_widget_item_calls, any_order=True)
mocked_author_item1.setData.assert_called_once_with(QtCore.Qt.UserRole, ANY)
@ -282,28 +277,26 @@ def test_reset_authors(MockedAuthor, MockedQListWidgetItem, form_env):
@patch('openlp.plugins.songs.forms.songmaintenanceform.QtWidgets.QListWidgetItem')
@patch('openlp.plugins.songs.forms.songmaintenanceform.Topic')
def test_reset_topics(MockedTopic, MockedQListWidgetItem, form_env):
def test_reset_topics(MockedTopic: MagicMock, MockedQListWidgetItem: MagicMock, maintenance_form: SongMaintenanceForm):
"""
Test the reset_topics() method
"""
# GIVEN: Some mocked out objects and methods
form = form_env[0]
mocked_manager = form_env[1]
MockedTopic.name = 'Grace'
mocked_topic = MagicMock()
mocked_topic.id = 1
mocked_topic.name = 'Grace'
mocked_manager.get_all_objects.return_value = [mocked_topic]
maintenance_form.manager.get_all_objects.return_value = [mocked_topic]
mocked_topic_item = MagicMock()
MockedQListWidgetItem.return_value = mocked_topic_item
# WHEN: reset_topics() is called
with patch.object(form, 'topics_list_widget') as mocked_topic_list_widget:
form.reset_topics()
with patch.object(maintenance_form, 'topics_list_widget') as mocked_topic_list_widget:
maintenance_form.reset_topics()
# THEN: The topics list should be reset correctly
mocked_topic_list_widget.clear.assert_called_once_with()
mocked_manager.get_all_objects.assert_called_once_with(MockedTopic)
maintenance_form.manager.get_all_objects.assert_called_once_with(MockedTopic)
MockedQListWidgetItem.assert_called_once_with('Grace')
mocked_topic_item.setData.assert_called_once_with(QtCore.Qt.UserRole, 1)
mocked_topic_list_widget.addItem.assert_called_once_with(mocked_topic_item)
@ -311,29 +304,28 @@ def test_reset_topics(MockedTopic, MockedQListWidgetItem, form_env):
@patch('openlp.plugins.songs.forms.songmaintenanceform.QtWidgets.QListWidgetItem')
@patch('openlp.plugins.songs.forms.songmaintenanceform.SongBook')
def test_reset_song_books(MockedBook, MockedQListWidgetItem, form_env):
def test_reset_song_books(MockedBook: MagicMock, MockedQListWidgetItem: MagicMock,
maintenance_form: SongMaintenanceForm):
"""
Test the reset_song_books() method
"""
# GIVEN: Some mocked out objects and methods
form = form_env[0]
mocked_manager = form_env[1]
MockedBook.name = 'Hymnal'
mocked_song_book = MagicMock()
mocked_song_book.id = 1
mocked_song_book.name = 'Hymnal'
mocked_song_book.publisher = 'Hymns and Psalms, Inc.'
mocked_manager.get_all_objects.return_value = [mocked_song_book]
maintenance_form.manager.get_all_objects.return_value = [mocked_song_book]
mocked_song_book_item = MagicMock()
MockedQListWidgetItem.return_value = mocked_song_book_item
# WHEN: reset_song_books() is called
with patch.object(form, 'song_books_list_widget') as mocked_song_book_list_widget:
form.reset_song_books()
with patch.object(maintenance_form, 'song_books_list_widget') as mocked_song_book_list_widget:
maintenance_form.reset_song_books()
# THEN: The song_books list should be reset correctly
mocked_song_book_list_widget.clear.assert_called_once_with()
mocked_manager.get_all_objects.assert_called_once_with(MockedBook)
maintenance_form.manager.get_all_objects.assert_called_once_with(MockedBook)
MockedQListWidgetItem.assert_called_once_with('Hymnal (Hymns and Psalms, Inc.)')
mocked_song_book_item.setData.assert_called_once_with(QtCore.Qt.UserRole, 1)
mocked_song_book_list_widget.addItem.assert_called_once_with(mocked_song_book_item)
@ -341,13 +333,11 @@ def test_reset_song_books(MockedBook, MockedQListWidgetItem, form_env):
@patch('openlp.plugins.songs.forms.songmaintenanceform.and_')
@patch('openlp.plugins.songs.forms.songmaintenanceform.Author')
def test_check_author_exists(MockedAuthor, mocked_and, form_env):
def test_check_author_exists(MockedAuthor: MagicMock, mocked_and: MagicMock, maintenance_form: SongMaintenanceForm):
"""
Test the check_author_exists() method
"""
# GIVEN: A bunch of mocked out stuff
form = form_env[0]
mocked_manager = form_env[1]
MockedAuthor.first_name = 'John'
MockedAuthor.last_name = 'Newton'
MockedAuthor.display_name = 'John Newton'
@ -357,54 +347,50 @@ def test_check_author_exists(MockedAuthor, mocked_and, form_env):
mocked_new_author.display_name = 'John Newton'
mocked_and.return_value = True
mocked_authors = [MagicMock(), MagicMock()]
mocked_manager.get_all_objects.return_value = mocked_authors
maintenance_form.manager.get_all_objects.return_value = mocked_authors
# WHEN: check_author_exists() is called
with patch.object(form, '_check_object_exists') as mocked_check_object_exists:
with patch.object(maintenance_form, '_check_object_exists') as mocked_check_object_exists:
mocked_check_object_exists.return_value = True
result = form.check_author_exists(mocked_new_author, edit=True)
result = maintenance_form.check_author_exists(mocked_new_author, edit=True)
# THEN: The correct result is returned
mocked_and.assert_called_once_with(True, True, True)
mocked_manager.get_all_objects.assert_called_once_with(MockedAuthor, True)
maintenance_form.manager.get_all_objects.assert_called_once_with(MockedAuthor, True)
mocked_check_object_exists.assert_called_once_with(mocked_authors, mocked_new_author, True)
assert result is True
@patch('openlp.plugins.songs.forms.songmaintenanceform.Topic')
def test_check_topic_exists(MockedTopic, form_env):
def test_check_topic_exists(MockedTopic: MagicMock, maintenance_form: SongMaintenanceForm):
"""
Test the check_topic_exists() method
"""
# GIVEN: Some mocked stuff
form = form_env[0]
mocked_manager = form_env[1]
MockedTopic.name = 'Grace'
mocked_new_topic = MagicMock()
mocked_new_topic.name = 'Grace'
mocked_topics = [MagicMock(), MagicMock()]
mocked_manager.get_all_objects.return_value = mocked_topics
maintenance_form.manager.get_all_objects.return_value = mocked_topics
# WHEN: check_topic_exists() is run
with patch.object(form, '_check_object_exists') as mocked_check_object_exists:
with patch.object(maintenance_form, '_check_object_exists') as mocked_check_object_exists:
mocked_check_object_exists.return_value = True
result = form.check_topic_exists(mocked_new_topic, True)
result = maintenance_form.check_topic_exists(mocked_new_topic, True)
# THEN: The correct things should have been called
mocked_manager.get_all_objects.assert_called_once_with(MockedTopic, True)
maintenance_form.manager.get_all_objects.assert_called_once_with(MockedTopic, True)
mocked_check_object_exists.assert_called_once_with(mocked_topics, mocked_new_topic, True)
assert result is True
@patch('openlp.plugins.songs.forms.songmaintenanceform.and_')
@patch('openlp.plugins.songs.forms.songmaintenanceform.SongBook')
def test_check_song_book_exists(MockedBook, mocked_and, form_env):
def test_check_song_book_exists(MockedBook: MagicMock, mocked_and: MagicMock, maintenance_form):
"""
Test the check_song_book_exists() method
"""
# GIVEN: Some mocked stuff
form = form_env[0]
mocked_manager = form_env[1]
MockedBook.name = 'Hymns'
MockedBook.publisher = 'Christian Songs'
mocked_new_book = MagicMock()
@ -412,84 +398,83 @@ def test_check_song_book_exists(MockedBook, mocked_and, form_env):
mocked_new_book.publisher = 'Christian Songs'
mocked_and.return_value = True
mocked_books = [MagicMock(), MagicMock()]
mocked_manager.get_all_objects.return_value = mocked_books
maintenance_form.manager.get_all_objects.return_value = mocked_books
# WHEN: check_book_exists() is run
with patch.object(form, '_check_object_exists') as mocked_check_object_exists:
with patch.object(maintenance_form, '_check_object_exists') as mocked_check_object_exists:
mocked_check_object_exists.return_value = True
result = form.check_song_book_exists(mocked_new_book, True)
result = maintenance_form.check_song_book_exists(mocked_new_book, True)
# THEN: The correct things should have been called
mocked_and.assert_called_once_with(True, True)
mocked_manager.get_all_objects.assert_called_once_with(MockedBook, True)
maintenance_form.manager.get_all_objects.assert_called_once_with(MockedBook, True)
mocked_check_object_exists.assert_called_once_with(mocked_books, mocked_new_book, True)
assert result is True
def test_check_object_exists_no_existing_objects(form_env):
def test_check_object_exists_no_existing_objects(maintenance_form: SongMaintenanceForm):
"""
Test the _check_object_exists() method when there are no existing objects
"""
# GIVEN: A SongMaintenanceForm instance
# WHEN: _check_object_exists() is called without existing objects
form = form_env[0]
result = form._check_object_exists([], None, False)
# THEN: The result should be True
assert result is True
assert maintenance_form._check_object_exists([], None, False) is True
def test_check_object_exists_without_edit(form_env):
def test_check_object_exists_without_edit(maintenance_form: SongMaintenanceForm):
"""
Test the _check_object_exists() method when edit is false
"""
# GIVEN: A SongMaintenanceForm instance
# WHEN: _check_object_exists() is called with edit set to false
form = form_env[0]
result = form._check_object_exists([MagicMock()], None, False)
# THEN: The result should be False
assert result is False
assert maintenance_form._check_object_exists([MagicMock()], None, False) is False
def test_check_object_exists_not_found(form_env):
def test_check_object_exists_not_found(maintenance_form: SongMaintenanceForm):
"""
Test the _check_object_exists() method when the object is not found
"""
# GIVEN: A SongMaintenanceForm instance and some mocked objects
form = form_env[0]
mocked_existing_objects = [MagicMock(id=1)]
mocked_new_object = MagicMock(id=2)
# WHEN: _check_object_exists() is called with edit set to false
result = form._check_object_exists(mocked_existing_objects, mocked_new_object, True)
# THEN: The result should be False
assert result is False
assert maintenance_form._check_object_exists(mocked_existing_objects, mocked_new_object, True) is False
def test_check_object_exists(form_env):
def test_check_object_exists(maintenance_form: SongMaintenanceForm):
"""
Test the _check_object_exists() method
"""
# GIVEN: A SongMaintenanceForm instance and some mocked objects
form = form_env[0]
mocked_existing_objects = [MagicMock(id=1)]
mocked_new_object = MagicMock(id=1)
# WHEN: _check_object_exists() is called with edit set to false
result = form._check_object_exists(mocked_existing_objects, mocked_new_object, True)
# THEN: The result should be False
assert result is True
assert maintenance_form._check_object_exists(mocked_existing_objects, mocked_new_object, True) is True
def test_merge_song_books(registry, settings, temp_folder):
def test_merge_song_books(request, registry: Registry, settings: Settings, temp_folder: str):
"""
Test the functionality of merging 2 song books.
"""
# GIVEN a test database populated with test data, and a song maintenance form
db_tmp_path = os.path.join(temp_folder, 'test-songs-2.9.2.sqlite')
db_tmp_path = os.path.join(temp_folder, 'test-song-maint-merge-songbooks.sqlite')
def cleanup_db():
try:
os.unlink(db_tmp_path)
except Exception:
# Ignore exceptions
pass
request.addfinalizer(cleanup_db)
# Create a db manager
manager = DBManager('songs', init_schema, db_file_path=db_tmp_path)
# create 2 song books, both with the same name
@ -567,3 +552,88 @@ def test_merge_song_books(registry, settings, temp_folder):
assert len(song3_book2_entry) == 1
# entry field should be overridden, as it was not set previously
assert song3_book2_entry[0].entry == '40'
def test_merge_authors(request, registry: Registry, settings: Settings, temp_folder: str):
"""
Test merging two authors
"""
# GIVEN a test database populated with test data, and a song maintenance form
db_tmp_path = os.path.join(temp_folder, 'test-song-maint-merge-authors.sqlite')
print(db_tmp_path)
# def cleanup_db():
# try:
# os.unlink(db_tmp_path)
# except Exception:
# # Ignore exceptions
# pass
# request.addfinalizer(cleanup_db)
# Create a db manager
manager = DBManager('songs', init_schema, db_file_path=db_tmp_path)
# create 2 song books, both with the same name
author1 = Author(first_name='John', last_name='Newton', display_name='John Newton')
manager.save_object(author1)
author2 = Author(first_name='John', last_name='Newton', display_name='John Newton')
manager.save_object(author2)
# create 3 songs, all with same search_title
song1 = Song()
song1.title = 'test song1'
song1.lyrics = 'lyrics1'
song1.search_title = 'test song'
song1.search_lyrics = 'lyrics1'
manager.save_object(song1)
song2 = Song()
song2.title = 'test song2'
song2.lyrics = 'lyrics2'
song2.search_title = 'test song'
song2.search_lyrics = 'lyrics2'
manager.save_object(song2)
song3 = Song()
song3.title = 'test song3'
song3.lyrics = 'lyrics3'
song3.search_title = 'test song'
song3.search_lyrics = 'lyrics3'
manager.save_object(song3)
# associate songs with authors
song1.add_author(author1)
song2.add_author(author1)
song3.add_author(author2)
manager.save_objects([song1, song2, song3])
song_maintenance_form = SongMaintenanceForm(manager)
# WHEN the song books are merged, getting rid of book1
song_maintenance_form.merge_authors(author1)
# THEN the database should reflect correctly the merge
songs = manager.get_all_objects(Song, Song.search_title == 'test song')
author_song1 = manager.get_all_objects(AuthorSong, AuthorSong.author_id == author1.id)
author_song2 = manager.get_all_objects(AuthorSong, AuthorSong.author_id == author2.id)
song1_author2 = manager.get_all_objects(AuthorSong, and_(AuthorSong.author_id == author2.id,
AuthorSong.song_id == song1.id))
song2_author2 = manager.get_all_objects(AuthorSong, and_(AuthorSong.author_id == author2.id,
AuthorSong.song_id == song2.id))
song3_author2 = manager.get_all_objects(AuthorSong, and_(AuthorSong.author_id == author2.id,
AuthorSong.song_id == song3.id))
authors = manager.get_all_objects(Author, Author.display_name == 'John Newton')
# song records should not be deleted
assert len(songs) == 3
# the old author should have been deleted
assert len(authors) == 1
# there should not be any songs associated with this author
assert len(author_song1) == 0
# each of the 3 songs should be associated with author2
assert len(author_song2) == 3
# the individual AuthorSong records should be correct
assert len(song1_author2) == 1
assert len(song2_author2) == 1
assert len(song3_author2) == 1