Пример #1
0
class TestMediaItem(TestCase, TestMixin):
    """
    Test the functions in the :mod:`lib` module.
    """
    def setUp(self):
        """
        Set up the components need for all tests.
        """
        Registry.create()
        Registry().register('service_list', MagicMock())
        Registry().register('main_window', MagicMock())
        self.mocked_plugin = MagicMock()
        with patch('openlp.core.lib.mediamanageritem.MediaManagerItem._setup'), \
                patch('openlp.plugins.songs.forms.editsongform.EditSongForm.__init__'):
            self.media_item = SongMediaItem(None, self.mocked_plugin)
            self.media_item.save_auto_select_id = MagicMock()
            self.media_item.list_view = MagicMock()
            self.media_item.list_view.save_auto_select_id = MagicMock()
            self.media_item.list_view.clear = MagicMock()
            self.media_item.list_view.addItem = MagicMock()
            self.media_item.list_view.setCurrentItem = MagicMock()
            self.media_item.auto_select_id = -1
            self.media_item.display_songbook = False
            self.media_item.display_copyright_symbol = False
        self.setup_application()
        self.build_settings()
        QtCore.QLocale.setDefault(QtCore.QLocale('en_GB'))

    def tearDown(self):
        """
        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):
        """
        Test displaying song search results with basic song
        """
        # GIVEN: Search results, 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.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
            self.media_item.list_view.clear.assert_called_with()
            self.media_item.save_auto_select_id.assert_called_with()
            MockedQListWidgetItem.assert_called_once_with(
                'My Song (My Author)')
            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)
            self.media_item.list_view.setCurrentItem.assert_called_with(
                mock_qlist_widget)

    def test_display_results_author(self):
        """
        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
            self.media_item.display_results_author(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 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):
        """
        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
        with patch('openlp.core.lib.QtWidgets.QListWidgetItem') as MockedQListWidgetItem, \
                patch('openlp.core.lib.QtCore.Qt.UserRole') as MockedUserRole:
            mock_search_results = [('1', 'My Book', 'My Song', 1)]
            mock_qlist_widget = MagicMock()
            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, plus a mocked QtListWidgetItem
        with patch('openlp.core.lib.QtWidgets.QListWidgetItem'
                   ) as MockedQListWidgetItem:
            mock_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)]
            mock_qlist_widget = MagicMock()
            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 songbooks are inserted in the right (natural) order,
            #       grouped first by book, then by number, then by song title
            calls = [
                call('My Book #1: My Song'),
                call().setData(QtCore.Qt.UserRole, 1),
                call('My Book #2: Your Song'),
                call().setData(QtCore.Qt.UserRole, 7),
                call('My Book #10: Our Song'),
                call().setData(QtCore.Qt.UserRole, 12),
                call('Thy Book #2: A Song'),
                call().setData(QtCore.Qt.UserRole, 8),
                call('Thy Book #2: Thy Song'),
                call().setData(QtCore.Qt.UserRole, 50)
            ]
            MockedQListWidgetItem.assert_has_calls(calls)

    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
            self.media_item.display_results_topic(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 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):
        """
        Test displaying song search results sorted by theme with basic song
        """
        # 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_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
            self.media_item.list_view.clear.assert_called_with()
            MockedQListWidgetItem.assert_called_once_with('My Theme (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_cclinumber(self):
        """
        Test displaying song search results sorted by CCLI number with basic song
        """
        # 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)

    @patch(u'openlp.plugins.songs.lib.mediaitem.Settings')
    def test_build_song_footer_one_author_show_written_by(
            self, MockedSettings):
        """
        Test build songs footer with basic song and one author
        """
        # GIVEN: A Song and a Service Item, mocked settings: True for 'songs/display written by'
        # and False for 'core/ccli number' (ccli will cause traceback if true)

        mocked_settings = MagicMock()
        mocked_settings.value.side_effect = [True, False]
        MockedSettings.return_value = mocked_settings

        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_song.authors_songs.append(mock_author_song)
        mock_song.copyright = 'My copyright'
        service_item = ServiceItem(None)

        # WHEN: I generate the Footer with default settings
        author_list = self.media_item.generate_footer(service_item, mock_song)

        # THEN: I get the following Array returned
        assert service_item.raw_footer == ['My Song', 'Written by: my author', 'My copyright'], \
            'The array should be returned correctly with a song, one author and copyright'
        assert author_list == [
            'my author'
        ], 'The author list should be returned correctly with one author'

    @patch(u'openlp.plugins.songs.lib.mediaitem.Settings')
    def test_build_song_footer_one_author_hide_written_by(
            self, MockedSettings):
        """
        Test build songs footer with basic song and one author
        """
        # GIVEN: A Song and a Service Item, mocked settings: False for 'songs/display written by'
        # and False for 'core/ccli number' (ccli will cause traceback if true)

        mocked_settings = MagicMock()
        mocked_settings.value.side_effect = [False, False]
        MockedSettings.return_value = mocked_settings

        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_song.authors_songs.append(mock_author_song)
        mock_song.copyright = 'My copyright'
        service_item = ServiceItem(None)

        # WHEN: I generate the Footer with default settings
        author_list = self.media_item.generate_footer(service_item, mock_song)

        # THEN: I get the following Array returned
        assert service_item.raw_footer == ['My Song', 'my author', 'My copyright'], \
            'The array should be returned correctly with a song, one author and copyright, ' \
            'text Written by should not be part of the text.'
        assert author_list == [
            'my author'
        ], 'The author list should be returned correctly with one author'

    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.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'
        service_item = ServiceItem(None)

        # WHEN: I generate the Footer with default settings
        author_list = self.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(self):
        """
        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'
        service_item = ServiceItem(None)
        Settings().setValue('core/ccli number', '1234')

        # WHEN: I generate the Footer with default settings
        self.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
        Settings().setValue('core/ccli number', '4321')
        self.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(self):
        """
        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.ccli_number = ''
        song.topics = None
        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 not be in the footer
        assert service_item.raw_footer == ['My Song', 'My copyright']

        # WHEN: I activate the "display songbook" option
        self.media_item.display_songbook = True
        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.title = 'My Song'
        mock_song.copyright = 'My copyright'
        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 be in the footer
        assert service_item.raw_footer == ['My Song', '© My copyright']

    def test_build_song_footer_copyright_disabled(self):
        """
        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'
        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'
Пример #2
0
class TestMediaItem(TestCase):
    """
    Test the functions in the :mod:`lib` module.
    """
    def setUp(self):
        """
        Set up the components need for all tests.
        """
        Registry.create()
        Registry().register('service_list', MagicMock())
        Registry().register('main_window', MagicMock())
        with patch('openlp.core.lib.mediamanageritem.MediaManagerItem.__init__'), \
                patch('openlp.plugins.songs.forms.editsongform.EditSongForm.__init__'):
            self.media_item = SongMediaItem(MagicMock(), MagicMock())

        fd, self.ini_file = mkstemp('.ini')
        Settings().set_filename(self.ini_file)
        self.application = QtGui.QApplication.instance()
        QtCore.QLocale.setDefault(QtCore.QLocale('en_GB'))

    def tearDown(self):
        """
        Delete all the C++ objects at the end so that we don't have a segfault
        """
        del self.application
        # Not all tests use settings!
        try:
            os.unlink(self.ini_file)
            os.unlink(Settings().fileName())
        except Exception:
            pass

    def build_song_footer_one_author_test(self):
        """
        Test build songs footer with basic song and one author
        """
        # GIVEN: A Song and a Service Item
        mock_song = MagicMock()
        mock_song.title = 'My Song'
        mock_author = MagicMock()
        mock_author.display_name = 'my author'
        mock_song.authors = []
        mock_song.authors.append(mock_author)
        mock_song.copyright = 'My copyright'
        service_item = ServiceItem(None)

        # WHEN: I generate the Footer with default settings
        author_list = self.media_item.generate_footer(service_item, mock_song)

        # THEN: I get the following Array returned
        self.assertEqual(service_item.raw_footer, ['My Song', 'my author', 'My copyright'],
                         'The array should be returned correctly with a song, one author and copyright')
        self.assertEqual(author_list, ['my author'],
                         'The author list should be returned correctly with one author')

    def build_song_footer_two_authors_test(self):
        """
        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_author = MagicMock()
        mock_author.display_name = 'my author'
        mock_song.authors = []
        mock_song.authors.append(mock_author)
        mock_author = MagicMock()
        mock_author.display_name = 'another author'
        mock_song.authors.append(mock_author)
        mock_song.copyright = 'My copyright'
        service_item = ServiceItem(None)

        # WHEN: I generate the Footer with default settings
        author_list = self.media_item.generate_footer(service_item, mock_song)

        # THEN: I get the following Array returned
        self.assertEqual(service_item.raw_footer, ['My Song', 'my author and another author', 'My copyright'],
                         'The array should be returned correctly with a song, two authors and copyright')
        self.assertEqual(author_list, ['my author', 'another author'],
                         'The author list should be returned correctly with two authors')

    def build_song_footer_base_ccli_test(self):
        """
        Test build songs footer with basic song and two authors
        """
        # GIVEN: A Song and a Service Item and a configured CCLI license
        mock_song = MagicMock()
        mock_song.title = 'My Song'
        mock_author = MagicMock()
        mock_author.display_name = 'my author'
        mock_song.authors = []
        mock_song.authors.append(mock_author)
        mock_song.copyright = 'My copyright'
        service_item = ServiceItem(None)
        Settings().setValue('core/ccli number', '1234')

        # WHEN: I generate the Footer with default settings
        self.media_item.generate_footer(service_item, mock_song)

        # THEN: I get the following Array returned
        self.assertEqual(service_item.raw_footer, ['My Song', 'my author', '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
        Settings().setValue('core/ccli number', '4321')
        self.media_item.generate_footer(service_item, mock_song)

        # THEN: I would get an amended footer string
        self.assertEqual(service_item.raw_footer, ['My Song', 'my author', 'My copyright', 'CCLI License: 4321'],
                         'The array should be returned correctly with a song, an author, copyright and amended ccli')
Пример #3
0
class TestMediaItem(TestCase, TestMixin):
    """
    Test the functions in the :mod:`lib` module.
    """
    def setUp(self):
        """
        Set up the components need for all tests.
        """
        Registry.create()
        Registry().register('service_list', MagicMock())
        Registry().register('main_window', MagicMock())
        with patch('openlp.core.lib.mediamanageritem.MediaManagerItem._setup'), \
                patch('openlp.plugins.songs.forms.editsongform.EditSongForm.__init__'):
            self.media_item = SongMediaItem(None, MagicMock())
            self.media_item.save_auto_select_id = MagicMock()
            self.media_item.list_view = MagicMock()
            self.media_item.list_view.save_auto_select_id = MagicMock()
            self.media_item.list_view.clear = MagicMock()
            self.media_item.list_view.addItem = MagicMock()
            self.media_item.list_view.setCurrentItem = MagicMock()
            self.media_item.auto_select_id = -1
            self.media_item.display_songbook = False
            self.media_item.display_copyright_symbol = False
        self.setup_application()
        self.build_settings()
        QtCore.QLocale.setDefault(QtCore.QLocale('en_GB'))

    def tearDown(self):
        """
        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):
        """
        Test displaying song search results with basic song
        """
        # GIVEN: Search results, 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.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
            self.media_item.list_view.clear.assert_called_with()
            self.media_item.save_auto_select_id.assert_called_with()
            MockedQListWidgetItem.assert_called_once_with('My Song (My Author)')
            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)
            self.media_item.list_view.setCurrentItem.assert_called_with(mock_qlist_widget)

    def test_display_results_author(self):
        """
        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
            self.media_item.display_results_author(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 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):
        """
        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
        with patch('openlp.core.lib.QtWidgets.QListWidgetItem') as MockedQListWidgetItem, \
                patch('openlp.core.lib.QtCore.Qt.UserRole') as MockedUserRole:
            mock_search_results = [('1', 'My Book', 'My Song', 1)]
            mock_qlist_widget = MagicMock()
            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, plus a mocked QtListWidgetItem
        with patch('openlp.core.lib.QtWidgets.QListWidgetItem') as MockedQListWidgetItem:
            mock_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)]
            mock_qlist_widget = MagicMock()
            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 songbooks are inserted in the right (natural) order,
            #       grouped first by book, then by number, then by song title
            calls = [call('My Book #1: My Song'), call().setData(QtCore.Qt.UserRole, 1),
                     call('My Book #2: Your Song'), call().setData(QtCore.Qt.UserRole, 7),
                     call('My Book #10: Our Song'), call().setData(QtCore.Qt.UserRole, 12),
                     call('Thy Book #2: A Song'), call().setData(QtCore.Qt.UserRole, 8),
                     call('Thy Book #2: Thy Song'), call().setData(QtCore.Qt.UserRole, 50)]
            MockedQListWidgetItem.assert_has_calls(calls)

    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
            self.media_item.display_results_topic(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 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):
        """
        Test displaying song search results sorted by theme with basic song
        """
        # 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_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
            self.media_item.list_view.clear.assert_called_with()
            MockedQListWidgetItem.assert_called_once_with('My Theme (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_cclinumber(self):
        """
        Test displaying song search results sorted by CCLI number with basic song
        """
        # 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)

    @patch(u'openlp.plugins.songs.lib.mediaitem.Settings')
    def test_build_song_footer_one_author_show_written_by(self, MockedSettings):
        """
        Test build songs footer with basic song and one author
        """
        # GIVEN: A Song and a Service Item, mocked settings: True for 'songs/display written by'
        # and False for 'core/ccli number' (ccli will cause traceback if true)

        mocked_settings = MagicMock()
        mocked_settings.value.side_effect = [True, False]
        MockedSettings.return_value = mocked_settings

        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_song.authors_songs.append(mock_author_song)
        mock_song.copyright = 'My copyright'
        service_item = ServiceItem(None)

        # WHEN: I generate the Footer with default settings
        author_list = self.media_item.generate_footer(service_item, mock_song)

        # THEN: I get the following Array returned
        self.assertEqual(service_item.raw_footer, ['My Song', 'Written by: my author', 'My copyright'],
                         'The array should be returned correctly with a song, one author and copyright')
        self.assertEqual(author_list, ['my author'],
                         'The author list should be returned correctly with one author')

    @patch(u'openlp.plugins.songs.lib.mediaitem.Settings')
    def test_build_song_footer_one_author_hide_written_by(self, MockedSettings):
        """
        Test build songs footer with basic song and one author
        """
        # GIVEN: A Song and a Service Item, mocked settings: False for 'songs/display written by'
        # and False for 'core/ccli number' (ccli will cause traceback if true)

        mocked_settings = MagicMock()
        mocked_settings.value.side_effect = [False, False]
        MockedSettings.return_value = mocked_settings

        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_song.authors_songs.append(mock_author_song)
        mock_song.copyright = 'My copyright'
        service_item = ServiceItem(None)

        # WHEN: I generate the Footer with default settings
        author_list = self.media_item.generate_footer(service_item, mock_song)

        # THEN: I get the following Array returned
        self.assertEqual(service_item.raw_footer, ['My Song', 'my author', 'My copyright'],
                         'The array should be returned correctly with a song, one author and copyright,'
                         'text Written by should not be part of the text.')
        self.assertEqual(author_list, ['my author'],
                         'The author list should be returned correctly with one author')

    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.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'
        service_item = ServiceItem(None)

        # WHEN: I generate the Footer with default settings
        author_list = self.media_item.generate_footer(service_item, mock_song)

        # THEN: I get the following Array returned
        self.assertEqual(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')
        self.assertEqual(author_list, ['another author', 'my author', 'translator'],
                         'The author list should be returned correctly with two authors')

    def test_build_song_footer_base_ccli(self):
        """
        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'
        service_item = ServiceItem(None)
        Settings().setValue('core/ccli number', '1234')

        # WHEN: I generate the Footer with default settings
        self.media_item.generate_footer(service_item, mock_song)

        # THEN: I get the following Array returned
        self.assertEqual(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
        Settings().setValue('core/ccli number', '4321')
        self.media_item.generate_footer(service_item, mock_song)

        # THEN: I would get an amended footer string
        self.assertEqual(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(self):
        """
        Test build songs footer with basic song and multiple songbooks
        """
        # GIVEN: A Song and a Service Item
        song = Song()
        song.title = 'My Song'
        song.copyright = 'My copyright'
        song.authors_songs = []
        song.songbook_entries = []
        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 not be in the footer
        self.assertEqual(service_item.raw_footer, ['My Song', 'My copyright'])

        # WHEN: I activate the "display songbook" option
        self.media_item.display_songbook = True
        self.media_item.generate_footer(service_item, song)

        # THEN: The songbook should be in the footer
        self.assertEqual(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.title = 'My Song'
        mock_song.copyright = 'My copyright'
        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 be in the footer
        self.assertEqual(service_item.raw_footer, ['My Song', '© My copyright'])

    def test_build_song_footer_copyright_disabled(self):
        """
        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'
        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
        self.assertEqual(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
        self.assertTrue(result, "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
        self.assertFalse(result, "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
        self.assertEqual(search_results, [[123, 'My Song', 'My alternative']])
Пример #4
0
class TestMediaItem(TestCase, TestMixin):
    """
    Test the functions in the :mod:`lib` module.
    """
    def setUp(self):
        """
        Set up the components need for all tests.
        """
        Registry.create()
        Registry().register('service_list', MagicMock())
        Registry().register('main_window', MagicMock())
        with patch('openlp.core.lib.mediamanageritem.MediaManagerItem._setup'), \
                patch('openlp.plugins.songs.forms.editsongform.EditSongForm.__init__'):
            self.media_item = SongMediaItem(None, MagicMock())
            self.media_item.display_songbook = False
            self.media_item.display_copyright_symbol = False
        self.setup_application()
        self.build_settings()
        QtCore.QLocale.setDefault(QtCore.QLocale('en_GB'))

    def tearDown(self):
        """
        Delete all the C++ objects at the end so that we don't have a segfault
        """
        self.destroy_settings()

    def build_song_footer_one_author_test(self):
        """
        Test build songs footer with basic song and one author
        """
        # 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_song.authors_songs.append(mock_author_song)
        mock_song.copyright = 'My copyright'
        service_item = ServiceItem(None)

        # WHEN: I generate the Footer with default settings
        author_list = self.media_item.generate_footer(service_item, mock_song)

        # THEN: I get the following Array returned
        self.assertEqual(service_item.raw_footer, ['My Song', 'Written by: my author', 'My copyright'],
                         'The array should be returned correctly with a song, one author and copyright')
        self.assertEqual(author_list, ['my author'],
                         'The author list should be returned correctly with one author')

    def build_song_footer_two_authors_test(self):
        """
        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'
        service_item = ServiceItem(None)

        # WHEN: I generate the Footer with default settings
        author_list = self.media_item.generate_footer(service_item, mock_song)

        # THEN: I get the following Array returned
        self.assertEqual(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')
        self.assertEqual(author_list, ['another author', 'my author', 'translator'],
                         'The author list should be returned correctly with two authors')

    def build_song_footer_base_ccli_test(self):
        """
        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'
        service_item = ServiceItem(None)
        Settings().setValue('core/ccli number', '1234')

        # WHEN: I generate the Footer with default settings
        self.media_item.generate_footer(service_item, mock_song)

        # THEN: I get the following Array returned
        self.assertEqual(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
        Settings().setValue('core/ccli number', '4321')
        self.media_item.generate_footer(service_item, mock_song)

        # THEN: I would get an amended footer string
        self.assertEqual(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 build_song_footer_base_songbook_test(self):
        """
        Test build songs footer with basic song and a songbook
        """
        # GIVEN: A Song and a Service Item
        mock_song = MagicMock()
        mock_song.title = 'My Song'
        mock_song.copyright = 'My copyright'
        mock_song.book = MagicMock()
        mock_song.book.name = "My songbook"
        mock_song.song_number = 12
        service_item = ServiceItem(None)

        # WHEN: I generate the Footer with default settings
        self.media_item.generate_footer(service_item, mock_song)

        # THEN: The songbook should not be in the footer
        self.assertEqual(service_item.raw_footer, ['My Song', 'My copyright'])

        # WHEN: I activate the "display songbook" option
        self.media_item.display_songbook = True
        self.media_item.generate_footer(service_item, mock_song)

        # THEN: The songbook should be in the footer
        self.assertEqual(service_item.raw_footer, ['My Song', 'My copyright', 'My songbook #12'])

    def build_song_footer_copyright_enabled_test(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.title = 'My Song'
        mock_song.copyright = 'My copyright'
        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 be in the footer
        self.assertEqual(service_item.raw_footer, ['My Song', '© My copyright'])

    def build_song_footer_copyright_disabled_test(self):
        """
        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'
        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
        self.assertEqual(service_item.raw_footer, ['My Song', 'My copyright'])

    def authors_match_test(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
        self.assertTrue(result, "Authors should match")

    def authors_dont_match_test(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
        self.assertFalse(result, "Authors should not match")