diff --git a/openlp/core/version.py b/openlp/core/version.py index 8ced4b307..7ba9c9b84 100644 --- a/openlp/core/version.py +++ b/openlp/core/version.py @@ -64,7 +64,7 @@ class VersionWorker(ThreadWorker): A worker class to fetch the version of OpenLP from the website. This is run from within a thread so that it doesn't affect the loading time of OpenLP. """ - new_version = QtCore.pyqtSignal(dict) + new_version = QtCore.pyqtSignal(str) no_internet = QtCore.pyqtSignal() def __init__(self, last_check_date, current_version): diff --git a/openlp/plugins/songs/reporting.py b/openlp/plugins/songs/reporting.py index 5682ce58b..955c0021f 100644 --- a/openlp/plugins/songs/reporting.py +++ b/openlp/plugins/songs/reporting.py @@ -47,7 +47,8 @@ def report_song_list(): translate('SongPlugin.ReportSongList', 'Save File'), Path(translate('SongPlugin.ReportSongList', 'song_extract.csv')), translate('SongPlugin.ReportSongList', 'CSV format (*.csv)')) - + if report_file_path is None: + return report_file_path.with_suffix('.csv') Registry().get('application').set_busy_cursor() try: diff --git a/tests/functional/openlp_plugins/songs/test_reporting.py b/tests/functional/openlp_plugins/songs/test_reporting.py new file mode 100644 index 000000000..ec83c82b4 --- /dev/null +++ b/tests/functional/openlp_plugins/songs/test_reporting.py @@ -0,0 +1,132 @@ +# -*- coding: utf-8 -*- + +########################################################################## +# OpenLP - Open Source Lyrics Projection # +# ---------------------------------------------------------------------- # +# Copyright (c) 2008-2020 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 report_song_list function. +""" +from unittest.mock import MagicMock, patch + +from openlp.core.common.registry import Registry +from openlp.plugins.songs.reporting import report_song_list + + +@patch('openlp.plugins.songs.reporting.csv') +@patch('openlp.plugins.songs.reporting.FileDialog') +def test_report_song_list(mock_file_dialog, mocked_csv, registry): + """ + Test that report_song_list works + """ + # GIVEN: A mocked save file and mocked song list + mock_file = MagicMock() + mock_file.open.side_effect = MagicMock() + mock_file_dialog.getSaveFileName = MagicMock(return_value=(mock_file, None)) + topic1 = MagicMock() + topic2 = MagicMock() + book1 = MagicMock() + book2 = MagicMock() + topic1.name = 'Topic 1' + topic2.name = 'Topic 2' + book1.name = 'Song Book 1' + book2.name = 'Song Book 2' + song_list = [MagicMock(**{ + 'title': 'The Song Title', + 'alternate_title': 'The alternate title', + 'copyright': 'The copyright', + 'authors_songs': [ + MagicMock(author=MagicMock(display_name='Bob')), + MagicMock(author=MagicMock(display_name='Bill')), + ], + 'songbook_entries': [ + MagicMock(entry='Book 1 entry', songbook=book1), + MagicMock(entry='Book 2 entry', songbook=book2), + ], + 'topics': [ + topic1, + topic2, + ] + })] + mocked_songs = MagicMock(plugin=MagicMock(manager=MagicMock(get_all_objects=MagicMock(return_value=song_list)))) + mocked_main_window = MagicMock() + mocked_application = MagicMock() + Registry().register('songs', mocked_songs) + Registry().register('main_window', mocked_main_window) + Registry().register('application', mocked_application) + mock_writer = MagicMock() + mocked_csv.DictWriter.return_value = mock_writer + + # WHEN: report_song_list is called + report_song_list() + + # THEN: getSaveFileName called, Busy cursor set and unset, writer called with correct values + mock_file_dialog.getSaveFileName.assert_called_once() + mocked_application.set_busy_cursor.assert_called_once() + mocked_application.set_normal_cursor.assert_called_once() + mock_writer.writerow.assert_called_with({ + 'Title': 'The Song Title', + 'Alternative Title': 'The alternate title', + 'Copyright': 'The copyright', + 'Author(s)': 'Bob | Bill', + 'Song Book': 'Song Book 1 #Book 1 entry | Song Book 2 #Book 2 entry', + 'Topic': 'Topic 1 | Topic 2' + }) + + +@patch('openlp.plugins.songs.reporting.log') +@patch('openlp.plugins.songs.reporting.FileDialog') +def test_report_song_list_error_reading(mock_file_dialog, mock_log, registry): + """ + Test that report song list sends an exception if the selected file location is not writable + """ + # GIVEN: A mocked file that returns a os error on open + def raise_os_error(x): + raise OSError + mock_file = MagicMock() + mock_file.open.side_effect = raise_os_error + mock_file_dialog.getSaveFileName = MagicMock(return_value=(mock_file, None)) + mocked_songs = MagicMock() + mocked_main_window = MagicMock() + mocked_application = MagicMock() + Registry().register('songs', mocked_songs) + Registry().register('main_window', mocked_main_window) + Registry().register('application', mocked_application) + + # WHEN: report_song_list is called + report_song_list() + + # THEN: getSaveFileName called, made exception log + mock_file_dialog.getSaveFileName.assert_called_once() + mock_log.exception.assert_called_once() + + +@patch('openlp.plugins.songs.reporting.FileDialog') +def test_report_song_list_cancel(mock_file_dialog, registry): + """ + Test that report song list does not crash if no file location was specified + """ + # GIVEN: getSaveFileName returns None + mock_file_dialog.getSaveFileName = MagicMock(return_value=(None, None)) + mocked_songs = MagicMock() + Registry().register('songs', mocked_songs) + + # WHEN: report_song_list is called + report_song_list() + + # THEN: Did not crash, and getSaveFileName was called + mock_file_dialog.getSaveFileName.assert_called_once()