From 704d9118a59b2ffe5ea551b55d2ded34c64afcab Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Mon, 7 Nov 2016 22:53:12 +0200 Subject: [PATCH] More tests --- .../presentations/lib/maclocontroller.py | 13 +- .../presentations/presentationplugin.py | 2 +- .../presentations/test_maclocontroller.py | 480 ++++++++++++++++++ 3 files changed, 482 insertions(+), 13 deletions(-) create mode 100644 tests/functional/openlp_plugins/presentations/test_maclocontroller.py diff --git a/openlp/plugins/presentations/lib/maclocontroller.py b/openlp/plugins/presentations/lib/maclocontroller.py index 85df2178f..91b30d0c8 100644 --- a/openlp/plugins/presentations/lib/maclocontroller.py +++ b/openlp/plugins/presentations/lib/maclocontroller.py @@ -20,17 +20,6 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### -# OOo API documentation: -# http://api.openoffice.org/docs/common/ref/com/sun/star/presentation/XSlideShowController.html -# http://wiki.services.openoffice.org/wiki/Documentation/DevGuide/ProUNO/Basic -# /Getting_Information_about_UNO_Objects#Inspecting_interfaces_during_debugging -# http://docs.go-oo.org/sd/html/classsd_1_1SlideShow.html -# http://www.oooforum.org/forum/viewtopic.phtml?t=5252 -# http://wiki.services.openoffice.org/wiki/Documentation/DevGuide/Working_with_Presentations -# http://mail.python.org/pipermail/python-win32/2008-January/006676.html -# http://www.linuxjournal.com/content/starting-stopping-and-connecting-openoffice-python -# http://nxsy.org/comparing-documents-with-openoffice-and-python - import logging import os import time @@ -65,7 +54,7 @@ class MacLOController(PresentationController): Initialise the class """ log.debug('Initialising') - super(MacLOController, self).__init__(plugin, 'MacLO', MacLODocument) + super(MacLOController, self).__init__(plugin, 'Impress on macOS', MacLODocument) self.supports = ['odp'] self.also_supports = ['ppt', 'pps', 'pptx', 'ppsx', 'pptm'] self.server_process = None diff --git a/openlp/plugins/presentations/presentationplugin.py b/openlp/plugins/presentations/presentationplugin.py index 505f0dbb7..8189b2b66 100644 --- a/openlp/plugins/presentations/presentationplugin.py +++ b/openlp/plugins/presentations/presentationplugin.py @@ -40,7 +40,7 @@ __default_settings__ = { 'presentations/override app': QtCore.Qt.Unchecked, 'presentations/enable_pdf_program': QtCore.Qt.Unchecked, 'presentations/pdf_program': '', - 'presentations/MacLO': QtCore.Qt.Checked, + 'presentations/Impress on macOS': QtCore.Qt.Checked, 'presentations/Impress': QtCore.Qt.Checked, 'presentations/Powerpoint': QtCore.Qt.Checked, 'presentations/Powerpoint Viewer': QtCore.Qt.Checked, diff --git a/tests/functional/openlp_plugins/presentations/test_maclocontroller.py b/tests/functional/openlp_plugins/presentations/test_maclocontroller.py new file mode 100644 index 000000000..b4948f7a7 --- /dev/null +++ b/tests/functional/openlp_plugins/presentations/test_maclocontroller.py @@ -0,0 +1,480 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2016 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; version 2 of the License. # +# # +# 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, write to the Free Software Foundation, Inc., 59 # +# Temple Place, Suite 330, Boston, MA 02111-1307 USA # +############################################################################### +""" +Functional tests to test the Mac LibreOffice class and related methods. +""" +from unittest import TestCase +import os +import shutil +from tempfile import mkdtemp + +from openlp.core.common import Settings +from openlp.plugins.presentations.lib.maclocontroller import \ + MacLOController, MacLODocument, TextType +from openlp.plugins.presentations.presentationplugin import __default_settings__ + +from tests.functional import MagicMock, patch, call +from tests.utils.constants import TEST_RESOURCES_PATH +from tests.helpers.testmixin import TestMixin + + +class TestMacLOController(TestCase, TestMixin): + """ + Test the MacLOController Class + """ + + def setUp(self): + """ + Set up the patches and mocks need for all tests. + """ + self.setup_application() + self.build_settings() + self.mock_plugin = MagicMock() + self.temp_folder = mkdtemp() + self.mock_plugin.settings_section = self.temp_folder + + def tearDown(self): + """ + Stop the patches + """ + self.destroy_settings() + shutil.rmtree(self.temp_folder) + + @patch('openlp.plugins.presentations.lib.maclocontroller.os') + @patch('openlp.plugins.presentations.lib.maclocontroller.Popen') + def test_constructor(self, MockedPopen, mocked_os): + """ + Test the Constructor from the MacLOController + """ + # GIVEN: No presentation controller + controller = None + mocked_process = MagicMock() + mocked_os.path.join.side_effect = lambda *x: '/'.join(x) + mocked_os.path.dirname.return_value = '' + MockedPopen.return_value = mocked_process + + # WHEN: The presentation controller object is created + controller = MacLOController(plugin=self.mock_plugin) + + # THEN: The name of the presentation controller should be correct + assert controller.name == 'Impress on macOS', \ + 'The name of the presentation controller should be correct' + MockedPopen.assert_called_once_with(['/Applications/LibreOffice.app/Contents/Resources/python', + '/libreofficeserver.py']) + assert controller.server_process == mocked_process + + @patch('openlp.plugins.presentations.lib.maclocontroller.MacLOController._start_server') + @patch('openlp.plugins.presentations.lib.maclocontroller.Proxy') + def test_client(self, MockedProxy, mocked_start_server): + """ + Test the client property of the Controller + """ + # GIVEN: A controller without a client and a mocked out Pyro + controller = MacLOController(plugin=self.mock_plugin) + mocked_client = MagicMock() + MockedProxy.return_value = mocked_client + mocked_client._pyroConnection = None + + # WHEN: the client property is called the first time + client = controller.client + + # THEN: a client is created + assert client == mocked_client + MockedProxy.assert_called_once_with('PYRO:openlp.libreofficeserver@localhost:4310') + mocked_client._pyroReconnect.assert_called_once_with() + + @patch('openlp.plugins.presentations.lib.maclocontroller.MacLOController._start_server') + def test_check_available(self, mocked_start_server): + """ + Test the check_available() method + """ + from openlp.plugins.presentations.lib.maclocontroller import macuno_available + + # GIVEN: A controller + controller = MacLOController(plugin=self.mock_plugin) + + # WHEN: check_available() is run + result = controller.check_available() + + # THEN: it should return false + assert result == macuno_available + + @patch('openlp.plugins.presentations.lib.maclocontroller.MacLOController._start_server') + def test_start_process(self, mocked_start_server): + """ + Test the start_process() method + """ + # GIVEN: A controller and a client + controller = MacLOController(plugin=self.mock_plugin) + controller._client = MagicMock() + + # WHEN: start_process() is called + controller.start_process() + + # THEN: The client's start_process() should have been called + controller._client.start_process.assert_called_once_with() + + + @patch('openlp.plugins.presentations.lib.maclocontroller.MacLOController._start_server') + def test_kill(self, mocked_start_server): + """ + Test the kill() method + """ + # GIVEN: A controller and a client + controller = MacLOController(plugin=self.mock_plugin) + controller._client = MagicMock() + controller.server_process = MagicMock() + + # WHEN: start_process() is called + controller.kill() + + # THEN: The client's start_process() should have been called + controller._client.shutdown.assert_called_once_with() + controller.server_process.kill.assert_called_once_with() + + +class TestMacLODocument(TestCase): + """ + Test the MacLODocument Class + """ + def setUp(self): + mocked_plugin = MagicMock() + mocked_plugin.settings_section = 'presentations' + Settings().extend_default_settings(__default_settings__) + self.file_name = os.path.join(TEST_RESOURCES_PATH, 'presentations', 'test.odp') + self.mocked_client = MagicMock() + with patch('openlp.plugins.presentations.lib.maclocontroller.MacLOController._start_server'): + self.controller = MacLOController(mocked_plugin) + self.controller._client = self.mocked_client + self.document = MacLODocument(self.controller, self.file_name) + + def test_load_presentation_no_desktop(self): + """ + Test the load_presentation() method when there's no desktop yet + """ + # GIVEN: A document and a mocked client + self.mocked_client.has_desktop.return_value = False + + # WHEN: load_presentation() is called + result = self.document.load_presentation() + + # THEN: Stuff should work right + self.mocked_client.setup_desktop.assert_called_once_with() + self.mocked_client.has_desktop.assert_called_once_with() + assert result is False + + @patch('openlp.plugins.presentations.lib.maclocontroller.ScreenList') + def test_load_presentation_cannot_load(self, MockedScreenList): + """ + Test the load_presentation() method when the server can't load the presentation + """ + # GIVEN: A document and a mocked client + mocked_screen_list = MagicMock() + MockedScreenList.return_value = mocked_screen_list + mocked_screen_list.current = {'number': 0} + self.mocked_client.has_desktop.return_value = True + self.mocked_client.load_presentation.return_value = False + + # WHEN: load_presentation() is called + result = self.document.load_presentation() + + # THEN: Stuff should work right + self.mocked_client.setup_desktop.assert_called_once_with() + self.mocked_client.has_desktop.assert_called_once_with() + self.mocked_client.load_presentation.assert_called_once_with(self.file_name, 1) + assert result is False + + @patch('openlp.plugins.presentations.lib.maclocontroller.ScreenList') + def test_load_presentation(self, MockedScreenList): + """ + Test the load_presentation() method + """ + # GIVEN: A document and a mocked client + mocked_screen_list = MagicMock() + MockedScreenList.return_value = mocked_screen_list + mocked_screen_list.current = {'number': 0} + self.mocked_client.has_desktop.return_value = True + self.mocked_client.load_presentation.return_value = True + + # WHEN: load_presentation() is called + with patch.object(self.document, 'create_thumbnails') as mocked_create_thumbnails, \ + patch.object(self.document, 'create_titles_and_notes') as mocked_create_titles_and_notes: + result = self.document.load_presentation() + + # THEN: Stuff should work right + self.mocked_client.setup_desktop.assert_called_once_with() + self.mocked_client.has_desktop.assert_called_once_with() + self.mocked_client.load_presentation.assert_called_once_with(self.file_name, 1) + mocked_create_thumbnails.assert_called_once_with() + mocked_create_titles_and_notes.assert_called_once_with() + assert result is True + + def test_create_thumbnails_already_exist(self): + """ + Test the create_thumbnails() method when thumbnails already exist + """ + # GIVEN: thumbnails that exist and a mocked client + self.document.check_thumbnails = MagicMock(return_value=True) + + # WHEN: create_thumbnails() is called + self.document.create_thumbnails() + + # THEN: The method should exit early + assert self.mocked_client.extract_thumbnails.call_count == 0 + + @patch('openlp.plugins.presentations.lib.maclocontroller.delete_file') + def test_create_thumbnails(self, mocked_delete_file): + """ + Test the create_thumbnails() method + """ + # GIVEN: thumbnails that don't exist and a mocked client + self.document.check_thumbnails = MagicMock(return_value=False) + self.mocked_client.extract_thumbnails.return_value = ['thumb1.png', 'thumb2.png'] + + # WHEN: create_thumbnails() is called + with patch.object(self.document, 'convert_thumbnail') as mocked_convert_thumbnail, \ + patch.object(self.document, 'get_temp_folder') as mocked_get_temp_folder: + mocked_get_temp_folder.return_value = 'temp' + self.document.create_thumbnails() + + # THEN: The method should complete successfully + self.mocked_client.extract_thumbnails.assert_called_once_with('temp') + assert mocked_convert_thumbnail.call_args_list == [ + call('thumb1.png', 1), call('thumb2.png', 2)] + assert mocked_delete_file.call_args_list == [call('thumb1.png'), call('thumb2.png')] + + def test_create_titles_and_notes(self): + """ + Test create_titles_and_notes() method + """ + # GIVEN: mocked client and mocked save_titles_and_notes() method + self.mocked_client.get_titles_and_notes.return_value = ('OpenLP', 'This is a note') + + # WHEN: create_titles_and_notes() is called + with patch.object(self.document, 'save_titles_and_notes') as mocked_save_titles_and_notes: + self.document.create_titles_and_notes() + + # THEN save_titles_and_notes should have been called + self.mocked_client.get_titles_and_notes.assert_called_once_with() + mocked_save_titles_and_notes.assert_called_once_with('OpenLP', 'This is a note') + + def test_close_presentation(self): + """ + Test the close_presentation() method + """ + # GIVEN: A mocked client and mocked remove_doc() method + # WHEN: close_presentation() is called + with patch.object(self.controller, 'remove_doc') as mocked_remove_doc: + self.document.close_presentation() + + # THEN: The presentation should have been closed + self.mocked_client.close_presentation.assert_called_once_with() + mocked_remove_doc.assert_called_once_with(self.document) + + def test_is_loaded(self): + """ + Test the is_loaded() method + """ + # GIVEN: A mocked client + self.mocked_client.is_loaded.return_value = True + + # WHEN: is_loaded() is called + result = self.document.is_loaded() + + # THEN: Then the result should be correct + assert result is True + + def test_is_active(self): + """ + Test the is_active() method + """ + # GIVEN: A mocked client + self.mocked_client.is_active.return_value = True + + # WHEN: is_active() is called + result = self.document.is_active() + + # THEN: Then the result should be correct + assert result is True + + def test_unblank_screen(self): + """ + Test the unblank_screen() method + """ + # GIVEN: A mocked client + self.mocked_client.unblank_screen.return_value = True + + # WHEN: unblank_screen() is called + result = self.document.unblank_screen() + + # THEN: Then the result should be correct + self.mocked_client.unblank_screen.assert_called_once_with() + assert result is True + + def test_blank_screen(self): + """ + Test the blank_screen() method + """ + # GIVEN: A mocked client + self.mocked_client.blank_screen.return_value = True + + # WHEN: blank_screen() is called + self.document.blank_screen() + + # THEN: Then the result should be correct + self.mocked_client.blank_screen.assert_called_once_with() + + def test_is_blank(self): + """ + Test the is_blank() method + """ + # GIVEN: A mocked client + self.mocked_client.is_blank.return_value = True + + # WHEN: is_blank() is called + result = self.document.is_blank() + + # THEN: Then the result should be correct + assert result is True + + def test_stop_presentation(self): + """ + Test the stop_presentation() method + """ + # GIVEN: A mocked client + self.mocked_client.stop_presentation.return_value = True + + # WHEN: stop_presentation() is called + self.document.stop_presentation() + + # THEN: Then the result should be correct + self.mocked_client.stop_presentation.assert_called_once_with() + + @patch('openlp.plugins.presentations.lib.maclocontroller.ScreenList') + @patch('openlp.plugins.presentations.lib.maclocontroller.Registry') + def test_start_presentation(self, MockedRegistry, MockedScreenList): + """ + Test the start_presentation() method + """ + # GIVEN: a mocked client, and multiple screens + mocked_screen_list = MagicMock() + mocked_registry = MagicMock() + mocked_main_window = MagicMock() + MockedScreenList.return_value = mocked_screen_list + MockedRegistry.return_value = mocked_registry + mocked_screen_list.screen_list = [0, 1] + mocked_registry.get.return_value = mocked_main_window + + # WHEN: start_presentation() is called + self.document.start_presentation() + + # THEN: The presentation should be started + self.mocked_client.start_presentation.assert_called_once_with() + mocked_registry.get.assert_called_once_with('main_window') + mocked_main_window.activateWindow.assert_called_once_with() + + def test_get_slide_number(self): + """ + Test the get_slide_number() method + """ + # GIVEN: A mocked client + self.mocked_client.get_slide_number.return_value = 5 + + # WHEN: get_slide_number() is called + result = self.document.get_slide_number() + + # THEN: Then the result should be correct + assert result == 5 + + def test_get_slide_count(self): + """ + Test the get_slide_count() method + """ + # GIVEN: A mocked client + self.mocked_client.get_slide_count.return_value = 8 + + # WHEN: get_slide_count() is called + result = self.document.get_slide_count() + + # THEN: Then the result should be correct + assert result == 8 + + def test_goto_slide(self): + """ + Test the goto_slide() method + """ + # GIVEN: A mocked client + # WHEN: goto_slide() is called + self.document.goto_slide(3) + + # THEN: Then the result should be correct + self.mocked_client.goto_slide.assert_called_once_with(3) + + def test_next_step(self): + """ + Test the next_step() method + """ + # GIVEN: A mocked client + # WHEN: next_step() is called + self.document.next_step() + + # THEN: Then the result should be correct + self.mocked_client.next_step.assert_called_once_with() + + def test_previous_step(self): + """ + Test the previous_step() method + """ + # GIVEN: A mocked client + # WHEN: previous_step() is called + self.document.previous_step() + + # THEN: Then the result should be correct + self.mocked_client.previous_step.assert_called_once_with() + + def test_get_slide_text(self): + """ + Test the get_slide_text() method + """ + # GIVEN: A mocked client + self.mocked_client.get_slide_text.return_value = 'Some slide text' + + # WHEN: get_slide_text() is called + result = self.document.get_slide_text(1) + + # THEN: Then the result should be correct + self.mocked_client.get_slide_text.assert_called_once_with(1) + assert result == 'Some slide text' + + def test_get_slide_notes(self): + """ + Test the get_slide_notes() method + """ + # GIVEN: A mocked client + self.mocked_client.get_slide_notes.return_value = 'This is a note' + + # WHEN: get_slide_notes() is called + result = self.document.get_slide_notes(2) + + # THEN: Then the result should be correct + self.mocked_client.get_slide_notes.assert_called_once_with(2) + assert result == 'This is a note'