Tests plugin 2

This commit is contained in:
Tim Bentley 2020-03-05 20:34:08 +00:00
parent 79950b6a85
commit 7d532778bd
8 changed files with 945 additions and 1286 deletions

View File

@ -0,0 +1,51 @@
# -*- 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 <https://www.gnu.org/licenses/>. #
##########################################################################
"""
For the Presentation tests
"""
import pytest
import shutil
from unittest.mock import MagicMock, patch
from tempfile import mkdtemp
from openlp.core.common.registry import Registry
from openlp.plugins.presentations.lib.mediaitem import PresentationMediaItem
@pytest.fixture
def media_item(settings):
"""Local test setup"""
Registry().register('service_manager', MagicMock())
Registry().register('main_window', MagicMock())
with patch('openlp.plugins.presentations.lib.mediaitem.MediaManagerItem._setup'), \
patch('openlp.plugins.presentations.lib.mediaitem.PresentationMediaItem.setup_item'):
m_item = PresentationMediaItem(None, MagicMock, MagicMock())
m_item.settings_section = 'media'
return m_item
@pytest.yield_fixture()
def mock_plugin():
m_plugin = MagicMock()
temp_folder = mkdtemp()
m_plugin.settings_section = temp_folder
yield m_plugin
shutil.rmtree(temp_folder)

View File

@ -21,295 +21,271 @@
""" """
Functional tests to test the Impress class and related methods. Functional tests to test the Impress class and related methods.
""" """
import shutil import pytest
from tempfile import mkdtemp
from unittest import TestCase
from unittest.mock import MagicMock, call, patch from unittest.mock import MagicMock, call, patch
from openlp.core.common.registry import Registry
from openlp.core.common.settings import Settings
from openlp.plugins.presentations.lib.impresscontroller import ImpressController, ImpressDocument, TextType from openlp.plugins.presentations.lib.impresscontroller import ImpressController, ImpressDocument, TextType
from tests.helpers.testmixin import TestMixin
from tests.utils.constants import RESOURCE_PATH from tests.utils.constants import RESOURCE_PATH
class TestImpressController(TestCase, TestMixin): @pytest.fixture()
def doc(settings):
mocked_plugin = MagicMock()
mocked_plugin.settings_section = 'presentations'
file_name = RESOURCE_PATH / 'presentations' / 'test.pptx'
ppc = ImpressController(mocked_plugin)
return ImpressDocument(ppc, file_name)
def test_constructor(settings, mock_plugin):
""" """
Test the ImpressController Class Test the Constructor from the ImpressController
""" """
# GIVEN: No presentation controller
controller = None
def setUp(self): # WHEN: The presentation controller object is created
""" controller = ImpressController(plugin=mock_plugin)
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
Registry.create()
Registry().register('settings', Settings())
def tearDown(self): # THEN: The name of the presentation controller should be correct
""" assert 'Impress' == controller.name, 'The name of the presentation controller should be correct'
Stop the patches
"""
self.destroy_settings()
shutil.rmtree(self.temp_folder)
def test_constructor(self):
"""
Test the Constructor from the ImpressController
"""
# GIVEN: No presentation controller
controller = None
# WHEN: The presentation controller object is created
controller = ImpressController(plugin=self.mock_plugin)
# THEN: The name of the presentation controller should be correct
assert 'Impress' == controller.name, 'The name of the presentation controller should be correct'
@patch('openlp.plugins.presentations.lib.impresscontroller.log')
def test_check_available(self, mocked_log):
"""
Test `ImpressController.check_available` on Windows
"""
# GIVEN: An instance of :class:`ImpressController`
controller = ImpressController(plugin=self.mock_plugin)
# WHEN: `check_available` is called on Windows and `get_com_servicemanager` returns None
with patch('openlp.plugins.presentations.lib.impresscontroller.is_win', return_value=True), \
patch.object(controller, 'get_com_servicemanager', return_value=None) as mocked_get_com_servicemanager:
result = controller.check_available()
# THEN: `check_available` should return False
assert mocked_get_com_servicemanager.called is True
assert result is False
@patch('openlp.plugins.presentations.lib.impresscontroller.log')
def test_check_available_on_windows(self, mocked_log):
"""
Test `ImpressController.check_available` on Windows
"""
# GIVEN: An instance of :class:`ImpressController`
controller = ImpressController(plugin=self.mock_plugin)
# WHEN: `check_available` is called on Windows and `get_com_servicemanager` returns an object
mocked_com_object = MagicMock()
with patch('openlp.plugins.presentations.lib.impresscontroller.is_win', return_value=True), \
patch.object(controller, 'get_com_servicemanager', return_value=mocked_com_object) \
as mocked_get_com_servicemanager:
result = controller.check_available()
# THEN: `check_available` should return True
assert mocked_get_com_servicemanager.called is True
assert result is True
@patch('openlp.plugins.presentations.lib.impresscontroller.log')
@patch('openlp.plugins.presentations.lib.impresscontroller.is_win', return_value=False)
def test_check_available_on_linux(self, mocked_is_win, mocked_log):
"""
Test `ImpressController.check_available` when not on Windows
"""
# GIVEN: An instance of :class:`ImpressController`
controller = ImpressController(plugin=self.mock_plugin)
# WHEN: `check_available` is called on Windows and `uno_available` is True
with patch('openlp.plugins.presentations.lib.impresscontroller.uno_available', True), \
patch.object(controller, 'get_com_servicemanager') as mocked_get_com_servicemanager:
result = controller.check_available()
# THEN: `check_available` should return True
assert mocked_get_com_servicemanager.called is False
assert result is True
@patch('openlp.plugins.presentations.lib.impresscontroller.is_win', return_value=True)
def test_start_process_on_windows(self, mocked_is_win):
"""
Test that start_process() on Windows starts the process
"""
# GIVEN: An ImpressController object
controller = ImpressController(plugin=self.mock_plugin)
controller.get_com_servicemanager = MagicMock(return_value=MagicMock())
# WHEN: start_process() is called
controller.start_process()
# THEN: The correct methods should have been called
controller.get_com_servicemanager.assert_called_once()
assert controller.manager._FlagAsMethod.call_args_list == [call('Bridge_GetStruct'),
call('Bridge_GetValueObject')]
@patch('openlp.plugins.presentations.lib.impresscontroller.is_win', return_value=False)
@patch('openlp.plugins.presentations.lib.impresscontroller.get_uno_command', return_value='libreoffice')
@patch('openlp.plugins.presentations.lib.impresscontroller.QtCore.QProcess')
def test_start_process_on_linux(self, MockQProcess, mocked_get_uno_command, mocked_is_win):
"""
Test that start_process() on Linux starts the process
"""
# GIVEN: An ImpressController object
mocked_process = MagicMock()
MockQProcess.return_value = mocked_process
controller = ImpressController(plugin=self.mock_plugin)
# WHEN: start_process() is called
controller.start_process()
# THEN: The correct methods should have been called
mocked_get_uno_command.assert_called_once()
MockQProcess.assert_called_once()
assert controller.process is mocked_process
mocked_process.startDetached.assert_called_once_with('libreoffice')
class TestImpressDocument(TestCase): @patch('openlp.plugins.presentations.lib.impresscontroller.log')
def test_check_available(mocked_log, settings, mock_plugin):
""" """
Test the ImpressDocument Class Test `ImpressController.check_available` on Windows
""" """
def setUp(self): # GIVEN: An instance of :class:`ImpressController`
mocked_plugin = MagicMock() controller = ImpressController(plugin=mock_plugin)
mocked_plugin.settings_section = 'presentations'
self.file_name = RESOURCE_PATH / 'presentations' / 'test.pptx'
self.settings = Settings()
Registry.create()
Registry().register('settings', self.settings)
self.ppc = ImpressController(mocked_plugin)
self.doc = ImpressDocument(self.ppc, self.file_name)
def test_create_titles_and_notes(self): # WHEN: `check_available` is called on Windows and `get_com_servicemanager` returns None
""" with patch('openlp.plugins.presentations.lib.impresscontroller.is_win', return_value=True), \
Test ImpressDocument.create_titles_and_notes patch.object(controller, 'get_com_servicemanager', return_value=None) as mocked_get_com_servicemanager:
""" result = controller.check_available()
# GIVEN: mocked PresentationController.save_titles_and_notes with
# 0 pages and the LibreOffice Document
self.doc.save_titles_and_notes = MagicMock()
self.doc.document = MagicMock()
self.doc.document.getDrawPages.return_value = MagicMock()
self.doc.document.getDrawPages().getCount.return_value = 0
# WHEN reading the titles and notes # THEN: `check_available` should return False
self.doc.create_titles_and_notes() assert mocked_get_com_servicemanager.called is True
assert result is False
# THEN save_titles_and_notes should have been called with empty arrays
self.doc.save_titles_and_notes.assert_called_once_with([], [])
# GIVEN: reset mock and set it to 2 pages @patch('openlp.plugins.presentations.lib.impresscontroller.log')
self.doc.save_titles_and_notes.reset_mock() def test_check_available_on_windows(mocked_log, settings, mock_plugin):
self.doc.document.getDrawPages().getCount.return_value = 2 """
Test `ImpressController.check_available` on Windows
"""
# GIVEN: An instance of :class:`ImpressController`
controller = ImpressController(plugin=mock_plugin)
# WHEN: a new call to create_titles_and_notes # WHEN: `check_available` is called on Windows and `get_com_servicemanager` returns an object
self.doc.create_titles_and_notes() mocked_com_object = MagicMock()
with patch('openlp.plugins.presentations.lib.impresscontroller.is_win', return_value=True), \
patch.object(controller, 'get_com_servicemanager', return_value=mocked_com_object) \
as mocked_get_com_servicemanager:
result = controller.check_available()
# THEN: save_titles_and_notes should have been called once with # THEN: `check_available` should return True
# two arrays of two elements assert mocked_get_com_servicemanager.called is True
# self.doc.save_titles_and_notes.assert_called_once_with(['\n', '\n'], [' ', ' ']) assert result is True
self.doc.save_titles_and_notes.assert_called_once_with(['', ''], [' ', ' '])
def test_get_text_from_page_out_of_bound(self):
"""
Test ImpressDocument.__get_text_from_page with out-of-bounds index
"""
# GIVEN: mocked LibreOffice Document with one slide,
# two notes and three texts
self.doc.document = self._mock_a_LibreOffice_document(1, 2, 3)
# WHEN: __get_text_from_page is called with an index of 0x00 @patch('openlp.plugins.presentations.lib.impresscontroller.log')
result = self.doc._ImpressDocument__get_text_from_page(0, TextType.Notes) @patch('openlp.plugins.presentations.lib.impresscontroller.is_win', return_value=False)
def test_check_available_on_linux(mocked_is_win, mocked_log, settings, mock_plugin):
"""
Test `ImpressController.check_available` when not on Windows
"""
# GIVEN: An instance of :class:`ImpressController`
controller = ImpressController(plugin=mock_plugin)
# THEN: the result should be an empty string # WHEN: `check_available` is called on Windows and `uno_available` is True
assert result == '', 'Result should be an empty string' with patch('openlp.plugins.presentations.lib.impresscontroller.uno_available', True), \
patch.object(controller, 'get_com_servicemanager') as mocked_get_com_servicemanager:
result = controller.check_available()
# WHEN: regardless of the type of text, index 0x00 is out of bounds # THEN: `check_available` should return True
result = self.doc._ImpressDocument__get_text_from_page(0, TextType.Title) assert mocked_get_com_servicemanager.called is False
assert result is True
# THEN: result should be an empty string
assert result == '', 'Result should be an empty string'
# WHEN: when called with 2, it should also be out of bounds @patch('openlp.plugins.presentations.lib.impresscontroller.is_win', return_value=True)
result = self.doc._ImpressDocument__get_text_from_page(2, TextType.SlideText) def test_start_process_on_windows(mocked_is_win, settings, mock_plugin):
"""
Test that start_process() on Windows starts the process
"""
# GIVEN: An ImpressController object
controller = ImpressController(plugin=mock_plugin)
controller.get_com_servicemanager = MagicMock(return_value=MagicMock())
# THEN: result should be an empty string ... and, getByIndex should # WHEN: start_process() is called
# have never been called controller.start_process()
assert result == '', 'Result should be an empty string'
assert self.doc.document.getDrawPages().getByIndex.call_count == 0, 'There should be no call to getByIndex'
def test_get_text_from_page_wrong_type(self): # THEN: The correct methods should have been called
""" controller.get_com_servicemanager.assert_called_once()
Test ImpressDocument.__get_text_from_page with wrong TextType assert controller.manager._FlagAsMethod.call_args_list == [call('Bridge_GetStruct'),
""" call('Bridge_GetValueObject')]
# GIVEN: mocked LibreOffice Document with one slide, two notes and
# three texts
self.doc.document = self._mock_a_LibreOffice_document(1, 2, 3)
# WHEN: called with TextType 3
result = self.doc._ImpressDocument__get_text_from_page(1, 3)
# THEN: result should be an empty string @patch('openlp.plugins.presentations.lib.impresscontroller.is_win', return_value=False)
assert result == '', 'Result should be and empty string' @patch('openlp.plugins.presentations.lib.impresscontroller.get_uno_command', return_value='libreoffice')
assert self.doc.document.getDrawPages().getByIndex.call_count == 0, 'There should be no call to getByIndex' @patch('openlp.plugins.presentations.lib.impresscontroller.QtCore.QProcess')
def test_start_process_on_linux(MockQProcess, mocked_get_uno_command, mocked_is_win, settings, mock_plugin):
"""
Test that start_process() on Linux starts the process
"""
# GIVEN: An ImpressController object
mocked_process = MagicMock()
MockQProcess.return_value = mocked_process
controller = ImpressController(plugin=mock_plugin)
def test_get_text_from_page_valid_params(self): # WHEN: start_process() is called
""" controller.start_process()
Test ImpressDocument.__get_text_from_page with valid parameters
"""
# GIVEN: mocked LibreOffice Document with one slide,
# two notes and three texts
self.doc.document = self._mock_a_LibreOffice_document(1, 2, 3)
# WHEN: __get_text_from_page is called to get the Notes # THEN: The correct methods should have been called
result = self.doc._ImpressDocument__get_text_from_page(1, TextType.Notes) mocked_get_uno_command.assert_called_once()
MockQProcess.assert_called_once()
assert controller.process is mocked_process
mocked_process.startDetached.assert_called_once_with('libreoffice')
# THEN: result should be 'Note\nNote\n'
assert result == 'Note\nNote\n', 'Result should be \'Note\\n\' times the count of notes in the page'
# WHEN: get the Title def test_create_titles_and_notes(doc):
result = self.doc._ImpressDocument__get_text_from_page(1, TextType.Title) """
Test ImpressDocument.create_titles_and_notes
"""
# GIVEN: mocked PresentationController.save_titles_and_notes with
# 0 pages and the LibreOffice Document
doc.save_titles_and_notes = MagicMock()
doc.document = MagicMock()
doc.document.getDrawPages.return_value = MagicMock()
doc.document.getDrawPages().getCount.return_value = 0
# THEN: result should be 'Title\n' # WHEN reading the titles and notes
assert result == 'Title\n', 'Result should be exactly \'Title\\n\'' doc.create_titles_and_notes()
# WHEN: get all text # THEN save_titles_and_notes should have been called with empty arrays
result = self.doc._ImpressDocument__get_text_from_page(1, TextType.SlideText) doc.save_titles_and_notes.assert_called_once_with([], [])
# THEN: result should be 'Title\nString\nString\n' # GIVEN: reset mock and set it to 2 pages
assert result == 'Title\nString\nString\n', 'Result should be exactly \'Title\\nString\\nString\\n\'' doc.save_titles_and_notes.reset_mock()
doc.document.getDrawPages().getCount.return_value = 2
def _mock_a_LibreOffice_document(self, page_count, note_count, text_count): # WHEN: a new call to create_titles_and_notes
""" doc.create_titles_and_notes()
Helper function, creates a mock libreoffice document.
:param page_count: Number of pages in the document # THEN: save_titles_and_notes should have been called once with
:param note_count: Number of note pages in the document # two arrays of two elements
:param text_count: Number of text pages in the document # self.doc.save_titles_and_notes.assert_called_once_with(['\n', '\n'], [' ', ' '])
""" doc.save_titles_and_notes.assert_called_once_with(['', ''], [' ', ' '])
pages = MagicMock()
page = MagicMock()
pages.getByIndex.return_value = page
notes_page = MagicMock()
notes_page.getCount.return_value = note_count
shape = MagicMock()
shape.supportsService.return_value = True
shape.getString.return_value = 'Note'
notes_page.getByIndex.return_value = shape
page.getNotesPage.return_value = notes_page
page.getCount.return_value = text_count
page.getByIndex.side_effect = self._get_page_shape_side_effect
pages.getCount.return_value = page_count
document = MagicMock()
document.getDrawPages.return_value = pages
document.getByIndex.return_value = page
return document
def _get_page_shape_side_effect(*args):
""" def test_get_text_from_page_out_of_bound(doc):
Helper function. """
""" Test ImpressDocument.__get_text_from_page with out-of-bounds index
page_shape = MagicMock() """
page_shape.supportsService.return_value = True # GIVEN: mocked LibreOffice Document with one slide,
if args[1] == 0: # two notes and three texts
page_shape.getShapeType.return_value = 'com.sun.star.presentation.TitleTextShape' doc.document = _mock_a_LibreOffice_document(1, 2, 3)
page_shape.getString.return_value = 'Title'
else: # WHEN: __get_text_from_page is called with an index of 0x00
page_shape.getString.return_value = 'String' result = doc._ImpressDocument__get_text_from_page(0, TextType.Notes)
return page_shape
# THEN: the result should be an empty string
assert result == '', 'Result should be an empty string'
# WHEN: regardless of the type of text, index 0x00 is out of bounds
result = doc._ImpressDocument__get_text_from_page(0, TextType.Title)
# THEN: result should be an empty string
assert result == '', 'Result should be an empty string'
# WHEN: when called with 2, it should also be out of bounds
result = doc._ImpressDocument__get_text_from_page(2, TextType.SlideText)
# THEN: result should be an empty string ... and, getByIndex should
# have never been called
assert result == '', 'Result should be an empty string'
assert doc.document.getDrawPages().getByIndex.call_count == 0, 'There should be no call to getByIndex'
def test_get_text_from_page_wrong_type(doc):
"""
Test ImpressDocument.__get_text_from_page with wrong TextType
"""
# GIVEN: mocked LibreOffice Document with one slide, two notes and
# three texts
doc.document = _mock_a_LibreOffice_document(1, 2, 3)
# WHEN: called with TextType 3
result = doc._ImpressDocument__get_text_from_page(1, 3)
# THEN: result should be an empty string
assert result == '', 'Result should be and empty string'
assert doc.document.getDrawPages().getByIndex.call_count == 0, 'There should be no call to getByIndex'
def test_get_text_from_page_valid_params(doc):
"""
Test ImpressDocument.__get_text_from_page with valid parameters
"""
# GIVEN: mocked LibreOffice Document with one slide,
# two notes and three texts
doc.document = _mock_a_LibreOffice_document(1, 2, 3)
# WHEN: __get_text_from_page is called to get the Notes
result = doc._ImpressDocument__get_text_from_page(1, TextType.Notes)
# THEN: result should be 'Note\nNote\n'
assert result == 'Note\nNote\n', 'Result should be \'Note\\n\' times the count of notes in the page'
# WHEN: get the Title
result = doc._ImpressDocument__get_text_from_page(1, TextType.Title)
# THEN: result should be 'Title\n'
assert result == 'Title\n', 'Result should be exactly \'Title\\n\''
# WHEN: get all text
result = doc._ImpressDocument__get_text_from_page(1, TextType.SlideText)
# THEN: result should be 'Title\nString\nString\n'
assert result == 'Title\nString\nString\n', 'Result should be exactly \'Title\\nString\\nString\\n\''
def _mock_a_LibreOffice_document(page_count, note_count, text_count):
"""
Helper function, creates a mock libreoffice document.
:param page_count: Number of pages in the document
:param note_count: Number of note pages in the document
:param text_count: Number of text pages in the document
"""
pages = MagicMock()
page = MagicMock()
pages.getByIndex.return_value = page
notes_page = MagicMock()
notes_page.getCount.return_value = note_count
shape = MagicMock()
shape.supportsService.return_value = True
shape.getString.return_value = 'Note'
notes_page.getByIndex.return_value = shape
page.getNotesPage.return_value = notes_page
page.getCount.return_value = text_count
page.getByIndex.side_effect = _get_page_shape_side_effect
pages.getCount.return_value = page_count
document = MagicMock()
document.getDrawPages.return_value = pages
document.getByIndex.return_value = page
return document
def _get_page_shape_side_effect(*args):
"""
Helper function.
"""
page_shape = MagicMock()
page_shape.supportsService.return_value = True
if args[0] == 0:
page_shape.getShapeType.return_value = 'com.sun.star.presentation.TitleTextShape'
page_shape.getString.return_value = 'Title'
else:
page_shape.getString.return_value = 'String'
return page_shape

View File

@ -22,145 +22,130 @@
This module contains tests for the lib submodule of the Presentations plugin. This module contains tests for the lib submodule of the Presentations plugin.
""" """
from pathlib import Path from pathlib import Path
from unittest import TestCase
from unittest.mock import MagicMock, PropertyMock, call, patch from unittest.mock import MagicMock, PropertyMock, call, patch
from openlp.core.common.registry import Registry from openlp.core.common.registry import Registry
from openlp.plugins.presentations.lib.mediaitem import PresentationMediaItem from openlp.plugins.presentations.lib.mediaitem import PresentationMediaItem
from tests.helpers.testmixin import TestMixin
class TestMediaItem(TestCase, TestMixin): def test_build_file_mask_string(media_item):
""" """
Test the mediaitem methods. Test the build_file_mask_string() method
""" """
def setUp(self): # GIVEN: Different controllers.
""" impress_controller = MagicMock()
Set up the components need for all tests. impress_controller.enabled.return_value = True
""" impress_controller.supports = ['odp']
Registry.create() impress_controller.also_supports = ['ppt']
Registry().register('service_manager', MagicMock()) presentation_controller = MagicMock()
Registry().register('main_window', MagicMock()) presentation_controller.enabled.return_value = True
with patch('openlp.plugins.presentations.lib.mediaitem.MediaManagerItem._setup'), \ presentation_controller.supports = ['ppt']
patch('openlp.plugins.presentations.lib.mediaitem.PresentationMediaItem.setup_item'): presentation_controller.also_supports = []
self.media_item = PresentationMediaItem(None, MagicMock, MagicMock()) presentation_viewer_controller = MagicMock()
self.setup_application() presentation_viewer_controller.enabled.return_value = False
pdf_controller = MagicMock()
pdf_controller.enabled.return_value = True
pdf_controller.supports = ['pdf']
pdf_controller.also_supports = ['xps', 'oxps', 'epub', 'cbz', 'fb2']
# Mock the controllers.
media_item.controllers = {
'Impress': impress_controller,
'Powerpoint': presentation_controller,
'Powerpoint Viewer': presentation_viewer_controller,
'Pdf': pdf_controller
}
def test_build_file_mask_string(self): # WHEN: Build the file mask.
""" with patch('openlp.plugins.presentations.lib.mediaitem.translate') as mocked_translate:
Test the build_file_mask_string() method mocked_translate.side_effect = lambda module, string_to_translate: string_to_translate
""" media_item.build_file_mask_string()
# GIVEN: Different controllers.
impress_controller = MagicMock()
impress_controller.enabled.return_value = True
impress_controller.supports = ['odp']
impress_controller.also_supports = ['ppt']
presentation_controller = MagicMock()
presentation_controller.enabled.return_value = True
presentation_controller.supports = ['ppt']
presentation_controller.also_supports = []
presentation_viewer_controller = MagicMock()
presentation_viewer_controller.enabled.return_value = False
pdf_controller = MagicMock()
pdf_controller.enabled.return_value = True
pdf_controller.supports = ['pdf']
pdf_controller.also_supports = ['xps', 'oxps', 'epub', 'cbz', 'fb2']
# Mock the controllers.
self.media_item.controllers = {
'Impress': impress_controller,
'Powerpoint': presentation_controller,
'Powerpoint Viewer': presentation_viewer_controller,
'Pdf': pdf_controller
}
# WHEN: Build the file mask. # THEN: The file mask should be generated correctly
with patch('openlp.plugins.presentations.lib.mediaitem.translate') as mocked_translate: assert '*.odp' in media_item.on_new_file_masks, 'The file mask should contain the odp extension'
mocked_translate.side_effect = lambda module, string_to_translate: string_to_translate assert '*.ppt' in media_item.on_new_file_masks, 'The file mask should contain the ppt extension'
self.media_item.build_file_mask_string() assert '*.pdf' in media_item.on_new_file_masks, 'The file mask should contain the pdf extension'
assert '*.xps' in media_item.on_new_file_masks, 'The file mask should contain the xps extension'
assert '*.oxps' in media_item.on_new_file_masks, 'The file mask should contain the oxps extension'
assert '*.epub' in media_item.on_new_file_masks, 'The file mask should contain the epub extension'
assert '*.cbz' in media_item.on_new_file_masks, 'The file mask should contain the cbz extension'
assert '*.fb2' in media_item.on_new_file_masks, 'The file mask should contain the fb2 extension'
# THEN: The file mask should be generated correctly
assert '*.odp' in self.media_item.on_new_file_masks, 'The file mask should contain the odp extension'
assert '*.ppt' in self.media_item.on_new_file_masks, 'The file mask should contain the ppt extension'
assert '*.pdf' in self.media_item.on_new_file_masks, 'The file mask should contain the pdf extension'
assert '*.xps' in self.media_item.on_new_file_masks, 'The file mask should contain the xps extension'
assert '*.oxps' in self.media_item.on_new_file_masks, 'The file mask should contain the oxps extension'
assert '*.epub' in self.media_item.on_new_file_masks, 'The file mask should contain the epub extension'
assert '*.cbz' in self.media_item.on_new_file_masks, 'The file mask should contain the cbz extension'
assert '*.fb2' in self.media_item.on_new_file_masks, 'The file mask should contain the fb2 extension'
def test_clean_up_thumbnails(self): def test_clean_up_thumbnails(media_item):
""" """
Test that the clean_up_thumbnails method works as expected when files exists. Test that the clean_up_thumbnails method works as expected when files exists.
""" """
# GIVEN: A mocked controller, and mocked os.path.getmtime # GIVEN: A mocked controller, and mocked os.path.getmtime
mocked_disabled_controller = MagicMock() mocked_disabled_controller = MagicMock()
mocked_disabled_controller.enabled.return_value = False mocked_disabled_controller.enabled.return_value = False
mocked_disabled_supports = PropertyMock() mocked_disabled_supports = PropertyMock()
type(mocked_disabled_controller).supports = mocked_disabled_supports type(mocked_disabled_controller).supports = mocked_disabled_supports
mocked_enabled_controller = MagicMock() mocked_enabled_controller = MagicMock()
mocked_enabled_controller.enabled.return_value = True mocked_enabled_controller.enabled.return_value = True
mocked_doc = MagicMock(**{'get_thumbnail_path.return_value': Path()}) mocked_doc = MagicMock(**{'get_thumbnail_path.return_value': Path()})
mocked_enabled_controller.add_document.return_value = mocked_doc mocked_enabled_controller.add_document.return_value = mocked_doc
mocked_enabled_controller.supports = ['tmp'] mocked_enabled_controller.supports = ['tmp']
self.media_item.controllers = { media_item.controllers = {
'Enabled': mocked_enabled_controller, 'Enabled': mocked_enabled_controller,
'Disabled': mocked_disabled_controller 'Disabled': mocked_disabled_controller
} }
thumb_path = MagicMock(st_mtime=100) thumb_path = MagicMock(st_mtime=100)
file_path = MagicMock(st_mtime=400) file_path = MagicMock(st_mtime=400)
with patch.object(Path, 'stat', side_effect=[thumb_path, file_path]), \ with patch.object(Path, 'stat', side_effect=[thumb_path, file_path]), \
patch.object(Path, 'exists', return_value=True): patch.object(Path, 'exists', return_value=True):
presentation_file = Path('file.tmp')
# WHEN: calling clean_up_thumbnails
self.media_item.clean_up_thumbnails(presentation_file, True)
# THEN: doc.presentation_deleted should have been called since the thumbnails mtime will be greater than
# the presentation_file's mtime.
mocked_doc.assert_has_calls([call.get_thumbnail_path(1, True), call.presentation_deleted()], True)
assert mocked_disabled_supports.call_count == 0
def test_clean_up_thumbnails_missing_file(self):
"""
Test that the clean_up_thumbnails method works as expected when file is missing.
"""
# GIVEN: A mocked controller, and mocked os.path.exists
mocked_controller = MagicMock()
mocked_doc = MagicMock()
mocked_controller.add_document.return_value = mocked_doc
mocked_controller.supports = ['tmp']
self.media_item.controllers = {
'Mocked': mocked_controller
}
presentation_file = Path('file.tmp') presentation_file = Path('file.tmp')
with patch.object(Path, 'exists', return_value=False):
# WHEN: calling clean_up_thumbnails # WHEN: calling clean_up_thumbnails
self.media_item.clean_up_thumbnails(presentation_file, True) media_item.clean_up_thumbnails(presentation_file, True)
# THEN: doc.presentation_deleted should have been called since the presentation file did not exists. # THEN: doc.presentation_deleted should have been called since the thumbnails mtime will be greater than
mocked_doc.assert_has_calls([call.get_thumbnail_path(1, True), call.presentation_deleted()], True) # the presentation_file's mtime.
mocked_doc.assert_has_calls([call.get_thumbnail_path(1, True), call.presentation_deleted()], True)
assert mocked_disabled_supports.call_count == 0
@patch('openlp.plugins.presentations.lib.mediaitem.MediaManagerItem._setup')
@patch('openlp.plugins.presentations.lib.mediaitem.PresentationMediaItem.setup_item')
def test_search(self, *unreferenced_mocks):
"""
Test that the search method finds the correct results
"""
# GIVEN: A mocked Settings class which returns a list of Path objects,
# and an instance of the PresentationMediaItem
path_1 = Path('some_dir', 'Impress_file_1')
path_2 = Path('some_other_dir', 'impress_file_2')
path_3 = Path('another_dir', 'ppt_file')
mocked_returned_settings = MagicMock()
mocked_returned_settings.value.return_value = [path_1, path_2, path_3]
Registry().register('settings', mocked_returned_settings)
media_item = PresentationMediaItem(None, MagicMock(), None)
media_item.settings_section = ''
# WHEN: Calling search def test_clean_up_thumbnails_missing_file(media_item):
results = media_item.search('IMPRE', False) """
Test that the clean_up_thumbnails method works as expected when file is missing.
"""
# GIVEN: A mocked controller, and mocked os.path.exists
mocked_controller = MagicMock()
mocked_doc = MagicMock()
mocked_controller.add_document.return_value = mocked_doc
mocked_controller.supports = ['tmp']
media_item.controllers = {
'Mocked': mocked_controller
}
presentation_file = Path('file.tmp')
with patch.object(Path, 'exists', return_value=False):
# THEN: The first two results should have been returned # WHEN: calling clean_up_thumbnails
assert results == [[str(path_1), 'Impress_file_1'], [str(path_2), 'impress_file_2']] media_item.clean_up_thumbnails(presentation_file, True)
# THEN: doc.presentation_deleted should have been called since the presentation file did not exists.
mocked_doc.assert_has_calls([call.get_thumbnail_path(1, True), call.presentation_deleted()], True)
@patch('openlp.plugins.presentations.lib.mediaitem.MediaManagerItem._setup')
@patch('openlp.plugins.presentations.lib.mediaitem.PresentationMediaItem.setup_item')
def test_search(mock_setup, mock_item, registry):
"""
Test that the search method finds the correct results
"""
# GIVEN: A mocked Settings class which returns a list of Path objects,
# and an instance of the PresentationMediaItem
path_1 = Path('some_dir', 'Impress_file_1')
path_2 = Path('some_other_dir', 'impress_file_2')
path_3 = Path('another_dir', 'ppt_file')
mocked_returned_settings = MagicMock()
mocked_returned_settings.value.return_value = [path_1, path_2, path_3]
Registry().register('settings', mocked_returned_settings)
media_item = PresentationMediaItem(None, MagicMock(), None)
media_item.settings_section = ''
# WHEN: Calling search
results = media_item.search('IMPRE', False)
# THEN: The first two results should have been returned
assert results == [[str(path_1), 'Impress_file_1'], [str(path_2), 'impress_file_2']]

View File

@ -21,129 +21,108 @@
""" """
This module contains tests for the lib submodule of the Presentations plugin. This module contains tests for the lib submodule of the Presentations plugin.
""" """
from unittest import TestCase
from unittest.mock import MagicMock, patch from unittest.mock import MagicMock, patch
from openlp.core.common.registry import Registry from openlp.plugins.presentations.lib.mediaitem import MessageListener
from openlp.plugins.presentations.lib.mediaitem import MessageListener, PresentationMediaItem
from openlp.plugins.presentations.lib.messagelistener import Controller from openlp.plugins.presentations.lib.messagelistener import Controller
from tests.helpers.testmixin import TestMixin
class TestMessageListener(TestCase, TestMixin): @patch('openlp.plugins.presentations.lib.mediaitem.MessageListener._setup')
def test_start_presentation(media_mock, media_item):
""" """
Test the Presentation Message Listener. Find and chose a controller to play a presentations.
""" """
def setUp(self): # GIVEN: A single controller and service item wanting to use the controller
""" mock_item = MagicMock()
Set up the components need for all tests. mock_item.processor = 'Powerpoint'
""" mock_item.get_frame_path.return_value = "test.ppt"
Registry.create() media_item.automatic = False
Registry().register('service_manager', MagicMock()) mocked_controller = MagicMock()
Registry().register('main_window', MagicMock()) mocked_controller.available = True
with patch('openlp.plugins.presentations.lib.mediaitem.MediaManagerItem._setup'), \ mocked_controller.supports = ['ppt']
patch('openlp.plugins.presentations.lib.mediaitem.PresentationMediaItem.setup_item'): controllers = {
self.media_item = PresentationMediaItem(None, MagicMock, MagicMock()) 'Powerpoint': mocked_controller
}
ml = MessageListener(media_item)
ml.media_item = media_item
ml.controllers = controllers
ml.preview_handler = MagicMock()
ml.timer = MagicMock()
@patch('openlp.plugins.presentations.lib.mediaitem.MessageListener._setup') # WHEN: request the presentation to start
def test_start_presentation(self, media_mock): ml.startup([mock_item, False, False, False])
"""
Find and chose a controller to play a presentations.
"""
# GIVEN: A single controller and service item wanting to use the controller
mock_item = MagicMock()
mock_item.processor = 'Powerpoint'
mock_item.get_frame_path.return_value = "test.ppt"
self.media_item.automatic = False
mocked_controller = MagicMock()
mocked_controller.available = True
mocked_controller.supports = ['ppt']
controllers = {
'Powerpoint': mocked_controller
}
ml = MessageListener(self.media_item)
ml.media_item = self.media_item
ml.controllers = controllers
ml.preview_handler = MagicMock()
ml.timer = MagicMock()
# WHEN: request the presentation to start # THEN: The controllers will be setup.
ml.startup([mock_item, False, False, False]) assert len(controllers) > 0, 'We have loaded a controller'
# THEN: The controllers will be setup.
assert len(controllers) > 0, 'We have loaded a controller'
@patch('openlp.plugins.presentations.lib.mediaitem.MessageListener._setup')
def test_start_presentation_with_no_player(self, media_mock):
"""
Find and chose a controller to play a presentations when the player is not available.
"""
# GIVEN: A single controller and service item wanting to use the controller
mock_item = MagicMock()
mock_item.processor = 'Powerpoint'
mock_item.get_frame_path.return_value = "test.ppt"
self.media_item.automatic = False
mocked_controller = MagicMock()
mocked_controller.available = True
mocked_controller.supports = ['ppt']
mocked_controller1 = MagicMock()
mocked_controller1.available = False
mocked_controller1.supports = ['ppt']
controllers = {
'Impress': mocked_controller,
'Powerpoint': mocked_controller1
}
ml = MessageListener(self.media_item)
ml.media_item = self.media_item
ml.controllers = controllers
ml.preview_handler = MagicMock()
ml.timer = MagicMock()
# WHEN: request the presentation to start
ml.startup([mock_item, False, False, False])
# THEN: The controllers will be setup.
assert len(controllers) > 0, 'We have loaded a controller'
@patch('openlp.plugins.presentations.lib.mediaitem.MessageListener._setup')
def test_start_pdf_presentation(self, media_mock):
"""
Test the startup of pdf presentation succeed.
"""
# GIVEN: A sservice item with a pdf
mock_item = MagicMock()
mock_item.processor = 'Pdf'
mock_item.get_frame_path.return_value = "test.pdf"
self.media_item.generate_slide_data = MagicMock()
ml = MessageListener(self.media_item)
ml.media_item = self.media_item
ml.preview_handler = MagicMock()
# WHEN: request the presentation to start
ml.startup([mock_item, False, False, False])
# THEN: The handler should be set to None
assert ml.handler is None, 'The handler should be None'
class TestController(TestCase, TestMixin): @patch('openlp.plugins.presentations.lib.mediaitem.MessageListener._setup')
def test_start_presentation_with_no_player(media_mock, media_item):
""" """
Test the Presentation Controller. Find and chose a controller to play a presentations when the player is not available.
""" """
# GIVEN: A single controller and service item wanting to use the controller
mock_item = MagicMock()
mock_item.processor = 'Powerpoint'
mock_item.get_frame_path.return_value = "test.ppt"
media_item.automatic = False
mocked_controller = MagicMock()
mocked_controller.available = True
mocked_controller.supports = ['ppt']
mocked_controller1 = MagicMock()
mocked_controller1.available = False
mocked_controller1.supports = ['ppt']
controllers = {
'Impress': mocked_controller,
'Powerpoint': mocked_controller1
}
ml = MessageListener(media_item)
ml.media_item = media_item
ml.controllers = controllers
ml.preview_handler = MagicMock()
ml.timer = MagicMock()
def test_add_handler_failure(self): # WHEN: request the presentation to start
""" ml.startup([mock_item, False, False, False])
Test that add_handler does set doc.slidenumber to 0 in case filed loading
"""
# GIVEN: A Controller, a mocked doc-controller
controller = Controller(True)
mocked_doc_controller = MagicMock()
mocked_doc = MagicMock()
mocked_doc.load_presentation.return_value = False
mocked_doc_controller.add_document.return_value = mocked_doc
# WHEN: calling add_handler that fails # THEN: The controllers will be setup.
controller.add_handler(mocked_doc_controller, MagicMock(), True, 0) assert len(controllers) > 0, 'We have loaded a controller'
# THEN: slidenumber should be 0
assert controller.doc.slidenumber == 0, 'doc.slidenumber should be 0' @patch('openlp.plugins.presentations.lib.mediaitem.MessageListener._setup')
def test_start_pdf_presentation(media_mock, media_item):
"""
Test the startup of pdf presentation succeed.
"""
# GIVEN: A sservice item with a pdf
mock_item = MagicMock()
mock_item.processor = 'Pdf'
mock_item.get_frame_path.return_value = "test.pdf"
media_item.generate_slide_data = MagicMock()
ml = MessageListener(media_item)
ml.media_item = media_item
ml.preview_handler = MagicMock()
# WHEN: request the presentation to start
ml.startup([mock_item, False, False, False])
# THEN: The handler should be set to None
assert ml.handler is None, 'The handler should be None'
def test_add_handler_failure():
"""
Test that add_handler does set doc.slidenumber to 0 in case filed loading
"""
# GIVEN: A Controller, a mocked doc-controller
controller = Controller(True)
mocked_doc_controller = MagicMock()
mocked_doc = MagicMock()
mocked_doc.load_presentation.return_value = False
mocked_doc_controller.add_document.return_value = mocked_doc
# WHEN: calling add_handler that fails
controller.add_handler(mocked_doc_controller, MagicMock(), True, 0)
# THEN: slidenumber should be 0
assert controller.doc.slidenumber == 0, 'doc.slidenumber should be 0'

View File

@ -26,25 +26,30 @@ import pytest
from pathlib import Path from pathlib import Path
from shutil import rmtree, which from shutil import rmtree, which
from tempfile import mkdtemp from tempfile import mkdtemp
from unittest import TestCase, skipIf
from unittest.mock import MagicMock, patch from unittest.mock import MagicMock, patch
from PyQt5 import QtCore, QtGui from PyQt5 import QtCore, QtGui
from openlp.core.common import is_macosx, is_linux, is_win from openlp.core.common import is_macosx, is_linux, is_win
from openlp.core.common.settings import Settings from openlp.core.common.settings import Settings
from openlp.core.common.registry import Registry
from openlp.core.display.screens import ScreenList from openlp.core.display.screens import ScreenList
from openlp.plugins.presentations.lib.pdfcontroller import PdfController, PdfDocument from openlp.plugins.presentations.lib.pdfcontroller import PdfController, PdfDocument
from tests.helpers.testmixin import TestMixin
from tests.utils.constants import RESOURCE_PATH from tests.utils.constants import RESOURCE_PATH
__default_settings__ = { @pytest.yield_fixture()
'presentations/enable_pdf_program': True, def pdf_env(settings, mock_plugin):
'presentations/pdf_program': None, temp_folder_path = Path(mkdtemp())
'presentations/thumbnail_scheme': '' thumbnail_folder_path = Path(mkdtemp())
} desktop = MagicMock()
desktop.primaryScreen.return_value = SCREEN['primary']
desktop.screenCount.return_value = SCREEN['number']
desktop.screenGeometry.return_value = SCREEN['size']
ScreenList.create(desktop)
yield settings, mock_plugin, temp_folder_path, thumbnail_folder_path
rmtree(thumbnail_folder_path)
rmtree(temp_folder_path)
SCREEN = { SCREEN = {
'primary': False, 'primary': False,
@ -66,195 +71,178 @@ def get_screen_resolution():
from win32api import GetSystemMetrics from win32api import GetSystemMetrics
return GetSystemMetrics(0), GetSystemMetrics(1) return GetSystemMetrics(0), GetSystemMetrics(1)
elif is_linux(): elif is_linux():
from Xlib.display import Display if IS_CI:
resolution = Display().screen().root.get_geometry() return 1024, 768
return resolution.width, resolution.height else:
from Xlib.display import Display
resolution = Display().screen().root.get_geometry()
return resolution.width, resolution.height
else: else:
return 1024, 768 return 1024, 768
class TestPdfController(TestCase, TestMixin): def test_constructor(settings, mock_plugin):
""" """
Test the PdfController. Test the Constructor from the PdfController
""" """
def setUp(self): # GIVEN: No presentation controller
""" controller = None
Set up the components need for all tests.
"""
Registry().create()
self.setup_application()
self.build_settings()
# Mocked out desktop object
self.desktop = MagicMock()
self.desktop.primaryScreen.return_value = SCREEN['primary']
self.desktop.screenCount.return_value = SCREEN['number']
self.desktop.screenGeometry.return_value = SCREEN['size']
Settings().extend_default_settings(__default_settings__)
Registry().register('settings', Settings())
self.screens = ScreenList.create(self.desktop)
self.temp_folder_path = Path(mkdtemp())
self.thumbnail_folder_path = Path(mkdtemp())
self.mock_plugin = MagicMock()
self.mock_plugin.settings_section = self.temp_folder_path
def tearDown(self): # WHEN: The presentation controller object is created
""" controller = PdfController(plugin=mock_plugin)
Delete all the C++ objects at the end so that we don't have a segfault
"""
del self.screens
Registry().remove('settings')
self.destroy_settings()
rmtree(self.thumbnail_folder_path)
rmtree(self.temp_folder_path)
def test_constructor(self): # THEN: The name of the presentation controller should be correct
""" assert 'Pdf' == controller.name, 'The name of the presentation controller should be correct'
Test the Constructor from the PdfController
"""
# GIVEN: No presentation controller
controller = None
# WHEN: The presentation controller object is created
controller = PdfController(plugin=self.mock_plugin)
# THEN: The name of the presentation controller should be correct def load_pdf(exe_path, pdf_env):
assert 'Pdf' == controller.name, 'The name of the presentation controller should be correct' """
Test loading a Pdf using the PdfController
"""
# GIVEN: A Pdf-file
test_file_path = RESOURCE_PATH / 'presentations' / 'pdf_test1.pdf'
@skipIf(IS_CI, "This is failing on CI, skip until we can figure out what the problem is") # WHEN: The Pdf is loaded
def load_pdf(self, exe_path): settings = pdf_env[0]
""" mock_plugin = pdf_env[1]
Test loading a Pdf using the PdfController temp_folder_path = pdf_env[2]
""" thumbnail_folder_path = pdf_env[3]
# GIVEN: A Pdf-file settings.setValue('presentations/pdf_program', exe_path)
test_file_path = RESOURCE_PATH / 'presentations' / 'pdf_test1.pdf' controller = PdfController(plugin=mock_plugin)
controller.temp_folder = temp_folder_path
controller.thumbnail_folder = thumbnail_folder_path
document = PdfDocument(controller, test_file_path)
loaded = document.load_presentation()
# WHEN: The Pdf is loaded # THEN: The load should succeed and we should be able to get a pagecount
Settings().setValue('presentations/pdf_program', exe_path) assert loaded is True, 'The loading of the PDF should succeed.'
controller = PdfController(plugin=self.mock_plugin) assert 3 == document.get_slide_count(), 'The pagecount of the PDF should be 3.'
controller.temp_folder = self.temp_folder_path
controller.thumbnail_folder = self.thumbnail_folder_path
document = PdfDocument(controller, test_file_path)
loaded = document.load_presentation()
# THEN: The load should succeed and we should be able to get a pagecount
assert loaded is True, 'The loading of the PDF should succeed.'
assert 3 == document.get_slide_count(), 'The pagecount of the PDF should be 3.'
def load_pdf_pictures(self, exe_path): def load_pdf_pictures(exe_path, pdf_env):
""" """
Test loading a Pdf and check the generated pictures' size Test loading a Pdf and check the generated pictures' size
""" """
# GIVEN: A Pdf-file # GIVEN: A Pdf-file
test_file_path = RESOURCE_PATH / 'presentations' / 'pdf_test1.pdf' test_file_path = RESOURCE_PATH / 'presentations' / 'pdf_test1.pdf'
# WHEN: The Pdf is loaded # WHEN: The Pdf is loaded
Settings().setValue('presentations/pdf_program', exe_path) mock_plugin = pdf_env[1]
controller = PdfController(plugin=self.mock_plugin) temp_folder_path = pdf_env[2]
controller.temp_folder = self.temp_folder_path thumbnail_folder_path = pdf_env[3]
controller.thumbnail_folder = self.thumbnail_folder_path Settings().setValue('presentations/pdf_program', exe_path)
document = PdfDocument(controller, test_file_path) controller = PdfController(plugin=mock_plugin)
loaded = document.load_presentation() controller.temp_folder = temp_folder_path
controller.thumbnail_folder = thumbnail_folder_path
document = PdfDocument(controller, test_file_path)
loaded = document.load_presentation()
# THEN: The load should succeed and pictures should be created and have been scaled to fit the screen # THEN: The load should succeed and pictures should be created and have been scaled to fit the screen
assert loaded is True, 'The loading of the PDF should succeed.' assert loaded is True, 'The loading of the PDF should succeed.'
image = QtGui.QImage(os.path.join(str(self.temp_folder_path), 'pdf_test1.pdf', 'mainslide001.png')) image = QtGui.QImage(os.path.join(str(temp_folder_path), 'pdf_test1.pdf', 'mainslide001.png'))
# Based on the converter used the resolution will differ a bit # Based on the converter used the resolution will differ a bit
if controller.gsbin: if controller.gsbin:
assert 1076 == image.height(), 'The height should be 1076' assert 1076 == image.height(), 'The height should be 1076'
assert 760 == image.width(), 'The width should be 760' assert 760 == image.width(), 'The width should be 760'
else: else:
width, height = get_screen_resolution() width, height = get_screen_resolution()
# Calculate the width of the PDF based on the aspect ratio of the PDF # Calculate the width of the PDF based on the aspect ratio of the PDF
width = int(round(height * 0.70703125, 0)) width = int(round(height * 0.70703125, 0))
assert image.height() == height, 'The height should be {height}'.format(height=height) assert image.height() == height, 'The height should be {height}'.format(height=height)
assert image.width() == width, 'The width should be {width}'.format(width=width) assert image.width() == width, 'The width should be {width}'.format(width=width)
def test_load_pdf(self):
"""
Test loading a Pdf with each of the installed backends
"""
for exe_name in ['gs', 'mutool', 'mudraw']:
exe_path = which(exe_name)
if exe_path:
self.load_pdf(exe_path)
self.load_pdf_pictures(exe_path)
def test_loading_pdf_using_pymupdf(self): def test_load_pdf(pdf_env):
try: """
import fitz # noqa: F401 Test loading a Pdf with each of the installed backends
except ImportError: """
pytest.skip('PyMuPDF is not installed') for exe_name in ['gs', 'mutool', 'mudraw']:
exe_path = which(exe_name)
if exe_path:
load_pdf(exe_path, pdf_env)
load_pdf_pictures(exe_path, pdf_env)
self.load_pdf(None)
self.load_pdf_pictures(None)
@patch('openlp.plugins.presentations.lib.pdfcontroller.check_binary_exists') def test_loading_pdf_using_pymupdf():
def test_process_check_binary_mudraw(self, mocked_check_binary_exists): try:
""" import fitz # noqa: F401
Test that the correct output from mudraw is detected except ImportError:
""" pytest.skip('PyMuPDF is not installed')
# GIVEN: A mocked check_binary_exists that returns mudraw output
mudraw_output = (b'usage: mudraw [options] input [pages]\n\t-o -\toutput filename (%d for page number)n\t\tsupp'
b'orted formats: pgm, ppm, pam, png, pbmn\t-p -\tpasswordn\t-r -\tresolution in dpi (default: '
b'72)n\t-w -\twidth (in pixels) (maximum width if -r is specified)n\t-h -\theight (in pixels) '
b'(maximum height if -r is specified)')
mocked_check_binary_exists.return_value = mudraw_output
# WHEN: Calling process_check_binary load_pdf(None)
ret = PdfController.process_check_binary('test') load_pdf_pictures(None)
# THEN: mudraw should be detected
assert 'mudraw' == ret, 'mudraw should have been detected'
@patch('openlp.plugins.presentations.lib.pdfcontroller.check_binary_exists') @patch('openlp.plugins.presentations.lib.pdfcontroller.check_binary_exists')
def test_process_check_binary_new_motool(self, mocked_check_binary_exists): def test_process_check_binary_mudraw(mocked_check_binary_exists):
""" """
Test that the correct output from the new mutool is detected Test that the correct output from mudraw is detected
""" """
# GIVEN: A mocked check_binary_exists that returns new mutool output # GIVEN: A mocked check_binary_exists that returns mudraw output
new_mutool_output = (b'usage: mutool <command> [options]\n\tdraw\t-- convert document\n\trun\t-- run javascript' mudraw_output = (b'usage: mudraw [options] input [pages]\n\t-o -\toutput filename (%d for page number)n\t\tsupp'
b'\n\tclean\t-- rewrite pdf file\n\textract\t-- extract font and image resources\n\tinfo\t' b'orted formats: pgm, ppm, pam, png, pbmn\t-p -\tpasswordn\t-r -\tresolution in dpi (default: '
b'-- show information about pdf resources\n\tpages\t-- show information about pdf pages\n' b'72)n\t-w -\twidth (in pixels) (maximum width if -r is specified)n\t-h -\theight (in pixels) '
b'\tposter\t-- split large page into many tiles\n\tshow\t-- show internal pdf objects\n\t' b'(maximum height if -r is specified)')
b'create\t-- create pdf document\n\tmerge\t-- merge pages from multiple pdf sources into a' mocked_check_binary_exists.return_value = mudraw_output
b'new pdf\n')
mocked_check_binary_exists.return_value = new_mutool_output
# WHEN: Calling process_check_binary # WHEN: Calling process_check_binary
ret = PdfController.process_check_binary('test') ret = PdfController.process_check_binary('test')
# THEN: mutool should be detected # THEN: mudraw should be detected
assert 'mutool' == ret, 'mutool should have been detected' assert 'mudraw' == ret, 'mudraw should have been detected'
@patch('openlp.plugins.presentations.lib.pdfcontroller.check_binary_exists')
def test_process_check_binary_old_motool(self, mocked_check_binary_exists):
"""
Test that the output from the old mutool is not accepted
"""
# GIVEN: A mocked check_binary_exists that returns old mutool output
old_mutool_output = (b'usage: mutool <command> [options]\n\tclean\t-- rewrite pdf file\n\textract\t-- extract '
b'font and image resources\n\tinfo\t-- show information about pdf resources\n\tposter\t-- '
b'split large page into many tiles\n\tshow\t-- show internal pdf objects')
mocked_check_binary_exists.return_value = old_mutool_output
# WHEN: Calling process_check_binary @patch('openlp.plugins.presentations.lib.pdfcontroller.check_binary_exists')
ret = PdfController.process_check_binary('test') def test_process_check_binary_new_motool(mocked_check_binary_exists):
"""
Test that the correct output from the new mutool is detected
"""
# GIVEN: A mocked check_binary_exists that returns new mutool output
new_mutool_output = (b'usage: mutool <command> [options]\n\tdraw\t-- convert document\n\trun\t-- run javascript'
b'\n\tclean\t-- rewrite pdf file\n\textract\t-- extract font and image resources\n\tinfo\t'
b'-- show information about pdf resources\n\tpages\t-- show information about pdf pages\n'
b'\tposter\t-- split large page into many tiles\n\tshow\t-- show internal pdf objects\n\t'
b'create\t-- create pdf document\n\tmerge\t-- merge pages from multiple pdf sources into a'
b'new pdf\n')
mocked_check_binary_exists.return_value = new_mutool_output
# THEN: mutool should be detected # WHEN: Calling process_check_binary
assert ret is None, 'old mutool should not be accepted!' ret = PdfController.process_check_binary('test')
@patch('openlp.plugins.presentations.lib.pdfcontroller.check_binary_exists') # THEN: mutool should be detected
def test_process_check_binary_gs(self, mocked_check_binary_exists): assert 'mutool' == ret, 'mutool should have been detected'
"""
Test that the correct output from gs is detected
"""
# GIVEN: A mocked check_binary_exists that returns gs output
gs_output = (b'GPL Ghostscript 9.19 (2016-03-23)\nCopyright (C) 2016 Artifex Software, Inc. All rights reserv'
b'ed.\nUsage: gs [switches] [file1.ps file2.ps ...]')
mocked_check_binary_exists.return_value = gs_output
# WHEN: Calling process_check_binary
ret = PdfController.process_check_binary('test')
# THEN: mutool should be detected @patch('openlp.plugins.presentations.lib.pdfcontroller.check_binary_exists')
assert 'gs' == ret, 'mutool should have been detected' def test_process_check_binary_old_motool(mocked_check_binary_exists):
"""
Test that the output from the old mutool is not accepted
"""
# GIVEN: A mocked check_binary_exists that returns old mutool output
old_mutool_output = (b'usage: mutool <command> [options]\n\tclean\t-- rewrite pdf file\n\textract\t-- extract '
b'font and image resources\n\tinfo\t-- show information about pdf resources\n\tposter\t-- '
b'split large page into many tiles\n\tshow\t-- show internal pdf objects')
mocked_check_binary_exists.return_value = old_mutool_output
# WHEN: Calling process_check_binary
ret = PdfController.process_check_binary('test')
# THEN: mutool should be detected
assert ret is None, 'old mutool should not be accepted!'
@patch('openlp.plugins.presentations.lib.pdfcontroller.check_binary_exists')
def test_process_check_binary_gs(mocked_check_binary_exists):
"""
Test that the correct output from gs is detected
"""
# GIVEN: A mocked check_binary_exists that returns gs output
gs_output = (b'GPL Ghostscript 9.19 (2016-03-23)\nCopyright (C) 2016 Artifex Software, Inc. All rights reserv'
b'ed.\nUsage: gs [switches] [file1.ps file2.ps ...]')
mocked_check_binary_exists.return_value = gs_output
# WHEN: Calling process_check_binary
ret = PdfController.process_check_binary('test')
# THEN: mutool should be detected
assert 'gs' == ret, 'mutool should have been detected'

View File

@ -21,287 +21,208 @@
""" """
Functional tests to test the PowerPointController class and related methods. Functional tests to test the PowerPointController class and related methods.
""" """
import os import pytest
import shutil
from tempfile import mkdtemp
from unittest import TestCase
from unittest.mock import MagicMock, patch from unittest.mock import MagicMock, patch
from openlp.core.common import is_win from openlp.core.common import is_win
from openlp.core.common.registry import Registry from openlp.core.common.registry import Registry
from openlp.core.common.settings import Settings
from openlp.plugins.presentations.lib.powerpointcontroller import PowerpointController, PowerpointDocument, \ from openlp.plugins.presentations.lib.powerpointcontroller import PowerpointController, PowerpointDocument, \
_get_text_from_shapes _get_text_from_shapes
from tests.helpers.testmixin import TestMixin
from tests.utils.constants import TEST_RESOURCES_PATH
if is_win(): if is_win():
import pywintypes import pywintypes
__default_settings__ = {
'presentations/powerpoint slide click advance': True @pytest.fixture()
} def get_thumbnail_folder(settings):
gtf = patch('openlp.plugins.presentations.lib.powerpointcontroller.PresentationDocument._setup')
yield gtf.start()
gtf.stop()
class TestPowerpointController(TestCase, TestMixin): def test_constructor(settings, mock_plugin):
""" """
Test the PowerpointController Class Test the Constructor from the PowerpointController
""" """
# GIVEN: No presentation controller
controller = None
def setUp(self): # WHEN: The presentation controller object is created
""" controller = PowerpointController(plugin=mock_plugin)
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
Registry.create()
Registry().register('settings', Settings())
def tearDown(self): # THEN: The name of the presentation controller should be correct
""" assert 'Powerpoint' == controller.name, 'The name of the presentation controller should be correct'
Stop the patches
"""
self.destroy_settings()
shutil.rmtree(self.temp_folder)
def test_constructor(self):
"""
Test the Constructor from the PowerpointController
"""
# GIVEN: No presentation controller
controller = None
# WHEN: The presentation controller object is created
controller = PowerpointController(plugin=self.mock_plugin)
# THEN: The name of the presentation controller should be correct
assert 'Powerpoint' == controller.name, 'The name of the presentation controller should be correct'
class TestPowerpointDocument(TestCase, TestMixin): def test_show_error_msg():
""" """
Test the PowerpointDocument Class Test the PowerpointDocument.show_error_msg() method gets called on com exception
""" """
if is_win():
# GIVEN: A PowerpointDocument with mocked controller and presentation
with patch('openlp.plugins.presentations.lib.powerpointcontroller.critical_error_message_box') as \
mocked_critical_error_message_box:
instance = PowerpointDocument(MagicMock(), MagicMock())
instance.presentation = MagicMock()
instance.presentation.SlideShowWindow.View.GotoSlide = MagicMock(side_effect=pywintypes.com_error('1'))
instance.index_map[42] = 42
def setUp(self): # WHEN: Calling goto_slide which will throw an exception
""" instance.goto_slide(42)
Set up the patches and mocks need for all tests.
"""
Registry.create()
Registry().register('settings', Settings())
self.setup_application()
self.build_settings()
self.mock_plugin = MagicMock()
self.temp_folder = mkdtemp()
self.mock_plugin.settings_section = self.temp_folder
self.powerpoint_document_stop_presentation_patcher = patch(
'openlp.plugins.presentations.lib.powerpointcontroller.PowerpointDocument.stop_presentation')
self.presentation_document_get_temp_folder_patcher = patch(
'openlp.plugins.presentations.lib.powerpointcontroller.PresentationDocument.get_temp_folder')
self.presentation_document_setup_patcher = patch(
'openlp.plugins.presentations.lib.powerpointcontroller.PresentationDocument._setup')
self.mock_powerpoint_document_stop_presentation = self.powerpoint_document_stop_presentation_patcher.start()
self.mock_presentation_document_get_temp_folder = self.presentation_document_get_temp_folder_patcher.start()
self.mock_presentation_document_setup = self.presentation_document_setup_patcher.start()
self.mock_controller = MagicMock()
self.mock_presentation = MagicMock()
self.mock_presentation_document_get_temp_folder.return_value = 'temp folder'
self.file_name = os.path.join(TEST_RESOURCES_PATH, 'presentations', 'test.pptx')
self.real_controller = PowerpointController(self.mock_plugin)
Settings().extend_default_settings(__default_settings__)
def tearDown(self): # THEN: mocked_critical_error_message_box should have been called
""" mocked_critical_error_message_box.assert_called_with('Error', 'An error occurred in the PowerPoint '
Stop the patches 'integration and the presentation will be stopped.'
""" ' Restart the presentation if you wish to '
self.powerpoint_document_stop_presentation_patcher.stop() 'present it.')
self.presentation_document_get_temp_folder_patcher.stop()
self.presentation_document_setup_patcher.stop()
self.destroy_settings()
shutil.rmtree(self.temp_folder)
def test_show_error_msg(self):
"""
Test the PowerpointDocument.show_error_msg() method gets called on com exception
"""
if is_win():
# GIVEN: A PowerpointDocument with mocked controller and presentation
with patch('openlp.plugins.presentations.lib.powerpointcontroller.critical_error_message_box') as \
mocked_critical_error_message_box:
instance = PowerpointDocument(self.mock_controller, self.mock_presentation)
instance.presentation = MagicMock()
instance.presentation.SlideShowWindow.View.GotoSlide = MagicMock(side_effect=pywintypes.com_error('1'))
instance.index_map[42] = 42
# WHEN: Calling goto_slide which will throw an exception def test_create_titles_and_notes(get_thumbnail_folder):
instance.goto_slide(42) """
Test creating the titles from PowerPoint
"""
# GIVEN: mocked save_titles_and_notes, _get_text_from_shapes and two mocked slides
doc = PowerpointDocument(MagicMock(), MagicMock())
doc.get_slide_count = MagicMock()
doc.get_slide_count.return_value = 2
doc.index_map = {1: 1, 2: 2}
doc.save_titles_and_notes = MagicMock()
doc._PowerpointDocument__get_text_from_shapes = MagicMock()
slide = MagicMock()
slide.Shapes.Title.TextFrame.TextRange.Text = 'SlideText'
pres = MagicMock()
pres.Slides = MagicMock(side_effect=[slide, slide])
doc.presentation = pres
# THEN: mocked_critical_error_message_box should have been called # WHEN reading the titles and notes
mocked_critical_error_message_box.assert_called_with('Error', 'An error occurred in the PowerPoint ' doc.create_titles_and_notes()
'integration and the presentation will be stopped.'
' Restart the presentation if you wish to '
'present it.')
# add _test to the following if necessary # THEN the save should have been called exactly once with 2 titles and 2 notes
def verify_loading_document(self): doc.save_titles_and_notes.assert_called_once_with(['SlideText', 'SlideText'], [' ', ' '])
"""
Test loading a document in PowerPoint
"""
if is_win() and self.real_controller.check_available():
# GIVEN: A PowerpointDocument and a presentation
doc = PowerpointDocument(self.real_controller, self.file_name)
# WHEN: loading the filename
doc.load_presentation()
result = doc.is_loaded()
# THEN: result should be true def test_create_titles_and_notes_with_no_slides(get_thumbnail_folder):
assert result is True, 'The result should be True' """
else: Test creating the titles from PowerPoint when it returns no slides
self.skipTest('Powerpoint not available, skipping test.') """
# GIVEN: mocked save_titles_and_notes, _get_text_from_shapes and two mocked slides
doc = PowerpointDocument(MagicMock(), MagicMock())
doc.save_titles_and_notes = MagicMock()
doc._PowerpointDocument__get_text_from_shapes = MagicMock()
pres = MagicMock()
pres.Slides = []
doc.presentation = pres
def test_create_titles_and_notes(self): # WHEN reading the titles and notes
""" doc.create_titles_and_notes()
Test creating the titles from PowerPoint
"""
# GIVEN: mocked save_titles_and_notes, _get_text_from_shapes and two mocked slides
self.doc = PowerpointDocument(self.mock_controller, self.file_name)
self.doc.get_slide_count = MagicMock()
self.doc.get_slide_count.return_value = 2
self.doc.index_map = {1: 1, 2: 2}
self.doc.save_titles_and_notes = MagicMock()
self.doc._PowerpointDocument__get_text_from_shapes = MagicMock()
slide = MagicMock()
slide.Shapes.Title.TextFrame.TextRange.Text = 'SlideText'
pres = MagicMock()
pres.Slides = MagicMock(side_effect=[slide, slide])
self.doc.presentation = pres
# WHEN reading the titles and notes # THEN the save should have been called exactly once with empty titles and notes
self.doc.create_titles_and_notes() doc.save_titles_and_notes.assert_called_once_with([], [])
# THEN the save should have been called exactly once with 2 titles and 2 notes
self.doc.save_titles_and_notes.assert_called_once_with(['SlideText', 'SlideText'], [' ', ' '])
def test_create_titles_and_notes_with_no_slides(self): def test_get_text_from_shapes():
""" """
Test creating the titles from PowerPoint when it returns no slides Test getting text from powerpoint shapes
""" """
# GIVEN: mocked save_titles_and_notes, _get_text_from_shapes and two mocked slides # GIVEN: mocked shapes
doc = PowerpointDocument(self.mock_controller, self.file_name) shape = MagicMock()
doc.save_titles_and_notes = MagicMock() shape.PlaceholderFormat.Type = 2
doc._PowerpointDocument__get_text_from_shapes = MagicMock() shape.HasTextFrame = shape.TextFrame.HasText = True
pres = MagicMock() shape.TextFrame.TextRange.Text = 'slideText'
pres.Slides = [] shapes = [shape, shape]
doc.presentation = pres
# WHEN reading the titles and notes # WHEN: getting the text
doc.create_titles_and_notes() result = _get_text_from_shapes(shapes)
# THEN the save should have been called exactly once with empty titles and notes # THEN: it should return the text
doc.save_titles_and_notes.assert_called_once_with([], []) assert result == 'slideText\nslideText\n', 'result should match \'slideText\nslideText\n\''
def test_get_text_from_shapes(self):
"""
Test getting text from powerpoint shapes
"""
# GIVEN: mocked shapes
shape = MagicMock()
shape.PlaceholderFormat.Type = 2
shape.HasTextFrame = shape.TextFrame.HasText = True
shape.TextFrame.TextRange.Text = 'slideText'
shapes = [shape, shape]
# WHEN: getting the text def test_get_text_from_shapes_with_no_shapes():
result = _get_text_from_shapes(shapes) """
Test getting text from powerpoint shapes with no shapes
"""
# GIVEN: empty shapes array
shapes = []
# THEN: it should return the text # WHEN: getting the text
assert result == 'slideText\nslideText\n', 'result should match \'slideText\nslideText\n\'' result = _get_text_from_shapes(shapes)
def test_get_text_from_shapes_with_no_shapes(self): # THEN: it should not fail but return empty string
""" assert result == '', 'result should be empty'
Test getting text from powerpoint shapes with no shapes
"""
# GIVEN: empty shapes array
shapes = []
# WHEN: getting the text
result = _get_text_from_shapes(shapes)
# THEN: it should not fail but return empty string def test_goto_slide(get_thumbnail_folder):
assert result == '', 'result should be empty' """
Test that goto_slide goes to next effect if the slide is already displayed
"""
# GIVEN: A Document with mocked controller, presentation, and mocked functions get_slide_number and next_step
Registry().get('settings').setValue('presentations/powerpoint slide click advance', True)
doc = PowerpointDocument(MagicMock(), MagicMock())
doc.presentation = MagicMock()
doc.presentation.SlideShowWindow.View.GetClickIndex.return_value = 1
doc.presentation.SlideShowWindow.View.GetClickCount.return_value = 2
doc.get_slide_number = MagicMock()
doc.get_slide_number.return_value = 1
doc.next_step = MagicMock()
doc.index_map[1] = 1
def test_goto_slide(self): # WHEN: Calling goto_slide
""" doc.goto_slide(1)
Test that goto_slide goes to next effect if the slide is already displayed
"""
# GIVEN: A Document with mocked controller, presentation, and mocked functions get_slide_number and next_step
doc = PowerpointDocument(self.mock_controller, self.mock_presentation)
doc.presentation = MagicMock()
doc.presentation.SlideShowWindow.View.GetClickIndex.return_value = 1
doc.presentation.SlideShowWindow.View.GetClickCount.return_value = 2
doc.get_slide_number = MagicMock()
doc.get_slide_number.return_value = 1
doc.next_step = MagicMock()
doc.index_map[1] = 1
# WHEN: Calling goto_slide # THEN: next_step() should be call to try to advance to the next effect.
doc.goto_slide(1) assert doc.next_step.called is True, 'next_step() should have been called!'
# THEN: next_step() should be call to try to advance to the next effect.
assert doc.next_step.called is True, 'next_step() should have been called!'
def test_blank_screen(self): def test_blank_screen(get_thumbnail_folder):
""" """
Test that blank_screen works as expected Test that blank_screen works as expected
""" """
# GIVEN: A Document with mocked controller, presentation, and mocked function get_slide_number # GIVEN: A Document with mocked controller, presentation, and mocked function get_slide_number
doc = PowerpointDocument(self.mock_controller, self.mock_presentation) doc = PowerpointDocument(MagicMock(), MagicMock())
doc.presentation = MagicMock()
doc.presentation.SlideShowWindow.View.GetClickIndex.return_value = 3
doc.presentation.Application.Version = 14.0
doc.get_slide_number = MagicMock()
doc.get_slide_number.return_value = 2
# WHEN: Calling goto_slide
doc.blank_screen()
# THEN: The view state, doc.blank_slide and doc.blank_click should have new values
assert doc.presentation.SlideShowWindow.View.State == 3, 'The View State should be 3'
assert doc.blank_slide == 2, 'doc.blank_slide should be 2 because of the PowerPoint version'
assert doc.blank_click == 3, 'doc.blank_click should be 3 because of the PowerPoint version'
def test_unblank_screen(get_thumbnail_folder):
"""
Test that unblank_screen works as expected
"""
# GIVEN: A Document with mocked controller, presentation, ScreenList, and mocked function get_slide_number
with patch('openlp.plugins.presentations.lib.powerpointcontroller.ScreenList') as mocked_screen_list:
mocked_screen_list_ret = MagicMock()
mocked_screen_list_ret.screen_list = [1]
mocked_screen_list.return_value = mocked_screen_list_ret
doc = PowerpointDocument(MagicMock(), MagicMock())
doc.presentation = MagicMock() doc.presentation = MagicMock()
doc.presentation.SlideShowWindow.View.GetClickIndex.return_value = 3 doc.presentation.SlideShowWindow.View.GetClickIndex.return_value = 3
doc.presentation.Application.Version = 14.0 doc.presentation.Application.Version = 14.0
doc.get_slide_number = MagicMock() doc.get_slide_number = MagicMock()
doc.get_slide_number.return_value = 2 doc.get_slide_number.return_value = 2
doc.index_map[1] = 1
doc.blank_slide = 1
doc.blank_click = 1
# WHEN: Calling goto_slide # WHEN: Calling goto_slide
doc.blank_screen() doc.unblank_screen()
# THEN: The view state, doc.blank_slide and doc.blank_click should have new values # THEN: The view state have new value, and several function should have been called
assert doc.presentation.SlideShowWindow.View.State == 3, 'The View State should be 3' assert doc.presentation.SlideShowWindow.View.State == 1, 'The View State should be 1'
assert doc.blank_slide == 2, 'doc.blank_slide should be 2 because of the PowerPoint version' assert doc.presentation.SlideShowWindow.Activate.called is True, \
assert doc.blank_click == 3, 'doc.blank_click should be 3 because of the PowerPoint version' 'SlideShowWindow.Activate should have been called'
assert doc.presentation.SlideShowWindow.View.GotoSlide.called is True, \
def test_unblank_screen(self): 'View.GotoSlide should have been called because of the PowerPoint version'
""" assert doc.presentation.SlideShowWindow.View.GotoClick.called is True, \
Test that unblank_screen works as expected 'View.GotoClick should have been called because of the PowerPoint version'
"""
# GIVEN: A Document with mocked controller, presentation, ScreenList, and mocked function get_slide_number
with patch('openlp.plugins.presentations.lib.powerpointcontroller.ScreenList') as mocked_screen_list:
mocked_screen_list_ret = MagicMock()
mocked_screen_list_ret.screen_list = [1]
mocked_screen_list.return_value = mocked_screen_list_ret
doc = PowerpointDocument(self.mock_controller, self.mock_presentation)
doc.presentation = MagicMock()
doc.presentation.SlideShowWindow.View.GetClickIndex.return_value = 3
doc.presentation.Application.Version = 14.0
doc.get_slide_number = MagicMock()
doc.get_slide_number.return_value = 2
doc.index_map[1] = 1
doc.blank_slide = 1
doc.blank_click = 1
# WHEN: Calling goto_slide
doc.unblank_screen()
# THEN: The view state have new value, and several function should have been called
assert doc.presentation.SlideShowWindow.View.State == 1, 'The View State should be 1'
assert doc.presentation.SlideShowWindow.Activate.called is True, \
'SlideShowWindow.Activate should have been called'
assert doc.presentation.SlideShowWindow.View.GotoSlide.called is True, \
'View.GotoSlide should have been called because of the PowerPoint version'
assert doc.presentation.SlideShowWindow.View.GotoClick.called is True, \
'View.GotoClick should have been called because of the PowerPoint version'

View File

@ -1,224 +0,0 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
##########################################################################
# 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 <https://www.gnu.org/licenses/>. #
##########################################################################
"""
This module contains tests for the pptviewcontroller module of the Presentations plugin.
"""
import shutil
from tempfile import mkdtemp
from unittest import TestCase, skipIf
from unittest.mock import MagicMock, patch
from openlp.core.common import is_win
from openlp.core.common.path import Path
from openlp.plugins.presentations.lib.pptviewcontroller import PptviewDocument, PptviewController
from tests.helpers.testmixin import TestMixin
from tests.utils.constants import RESOURCE_PATH
class TestPptviewController(TestCase, TestMixin):
"""
Test the PptviewController 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)
def test_constructor(self):
"""
Test the Constructor from the PptViewController
"""
# GIVEN: No presentation controller
controller = None
# WHEN: The presentation controller object is created
controller = PptviewController(plugin=self.mock_plugin)
# THEN: The name of the presentation controller should be correct
assert 'Powerpoint Viewer' == controller.name, 'The name of the presentation controller should be correct'
@skipIf(not is_win(), 'Not Windows')
@patch('openlp.plugins.presentations.lib.pptviewcontroller.cdll.LoadLibrary')
def test_check_available(self, mocked_load_library):
"""
Test check_available / check_installed
"""
# GIVEN: A mocked dll loader and a controller
mocked_process = MagicMock()
mocked_process.CheckInstalled.return_value = True
mocked_load_library.return_value = mocked_process
controller = PptviewController(plugin=self.mock_plugin)
# WHEN: check_available is called
available = controller.check_available()
# THEN: On windows it should return True, on other platforms False
assert available is True, 'check_available should return True on windows.'
class TestPptviewDocument(TestCase):
"""
Test the PptviewDocument Class
"""
def setUp(self):
"""
Set up the patches and mocks need for all tests.
"""
self.pptview_document_create_thumbnails_patcher = patch(
'openlp.plugins.presentations.lib.pptviewcontroller.PptviewDocument.create_thumbnails')
self.pptview_document_stop_presentation_patcher = patch(
'openlp.plugins.presentations.lib.pptviewcontroller.PptviewDocument.stop_presentation')
self.presentation_document_get_temp_folder_patcher = patch(
'openlp.plugins.presentations.lib.pptviewcontroller.PresentationDocument.get_temp_folder')
self.presentation_document_setup_patcher = patch(
'openlp.plugins.presentations.lib.pptviewcontroller.PresentationDocument._setup')
self.screen_list_patcher = patch('openlp.plugins.presentations.lib.pptviewcontroller.ScreenList')
self.rect_patcher = MagicMock()
self.mock_pptview_document_create_thumbnails = self.pptview_document_create_thumbnails_patcher.start()
self.mock_pptview_document_stop_presentation = self.pptview_document_stop_presentation_patcher.start()
self.mock_presentation_document_get_temp_folder = self.presentation_document_get_temp_folder_patcher.start()
self.mock_presentation_document_setup = self.presentation_document_setup_patcher.start()
self.mock_rect = self.rect_patcher.start()
self.mock_screen_list = self.screen_list_patcher.start()
self.mock_controller = MagicMock()
self.mock_presentation = MagicMock()
self.temp_folder = mkdtemp()
self.mock_presentation_document_get_temp_folder.return_value = self.temp_folder
def tearDown(self):
"""
Stop the patches
"""
self.pptview_document_create_thumbnails_patcher.stop()
self.pptview_document_stop_presentation_patcher.stop()
self.presentation_document_get_temp_folder_patcher.stop()
self.presentation_document_setup_patcher.stop()
self.rect_patcher.stop()
self.screen_list_patcher.stop()
shutil.rmtree(self.temp_folder)
@skipIf(not is_win(), 'Not Windows')
def test_load_presentation_succesful(self):
"""
Test the PptviewDocument.load_presentation() method when the PPT is successfully opened
"""
# GIVEN: A reset mocked_os
self.mock_controller.process.OpenPPT.return_value = 0
instance = PptviewDocument(self.mock_controller, self.mock_presentation)
instance.file_path = 'test\path.ppt'
# WHEN: The temporary directory exists and OpenPPT returns successfully (not -1)
result = instance.load_presentation()
# THEN: PptviewDocument.load_presentation should return True
assert result is True
@skipIf(not is_win(), 'Not Windows')
def test_load_presentation_un_succesful(self):
"""
Test the PptviewDocument.load_presentation() method when the temporary directory does not exist and the PPT is
not successfully opened
"""
# GIVEN: A reset mock_os_isdir
self.mock_controller.process.OpenPPT.return_value = -1
instance = PptviewDocument(self.mock_controller, self.mock_presentation)
instance.file_path = 'test\path.ppt'
# WHEN: The temporary directory does not exist and OpenPPT returns unsuccessfully (-1)
with patch.object(instance, 'get_temp_folder') as mocked_get_folder:
mocked_get_folder.return_value = MagicMock(spec=Path)
result = instance.load_presentation()
# THEN: The temp folder should be created and PptviewDocument.load_presentation should return False
assert result is False
def test_create_titles_and_notes(self):
"""
Test PowerpointController.create_titles_and_notes
"""
# GIVEN: mocked PresentationController.save_titles_and_notes and a pptx file
doc = PptviewDocument(self.mock_controller, self.mock_presentation)
doc.file_path = RESOURCE_PATH / 'presentations' / 'test.pptx'
doc.save_titles_and_notes = MagicMock()
# WHEN reading the titles and notes
doc.create_titles_and_notes()
# THEN save_titles_and_notes should have been called once with empty arrays
doc.save_titles_and_notes.assert_called_once_with(['Test 1\n', '\n', 'Test 2\n', 'Test 4\n', 'Test 3\n'],
['Notes for slide 1', 'Inserted', 'Notes for slide 2',
'Notes \nfor slide 4', 'Notes for slide 3'])
def test_create_titles_and_notes_nonexistent_file(self):
"""
Test PowerpointController.create_titles_and_notes with nonexistent file
"""
# GIVEN: mocked PresentationController.save_titles_and_notes and an nonexistent file
with patch('builtins.open') as mocked_open, \
patch.object(Path, 'exists') as mocked_path_exists, \
patch('openlp.plugins.presentations.lib.presentationcontroller.create_paths') as \
mocked_dir_exists:
mocked_path_exists.return_value = False
mocked_dir_exists.return_value = False
doc = PptviewDocument(self.mock_controller, self.mock_presentation)
doc.file_path = Path('Idontexist.pptx')
doc.save_titles_and_notes = MagicMock()
# WHEN: Reading the titles and notes
doc.create_titles_and_notes()
# THEN: File existens should have been checked, and not have been opened.
doc.save_titles_and_notes.assert_called_once_with(None, None)
mocked_path_exists.assert_called_with()
assert mocked_open.call_count == 0, 'There should be no calls to open a file.'
def test_create_titles_and_notes_invalid_file(self):
"""
Test PowerpointController.create_titles_and_notes with invalid file
"""
# GIVEN: mocked PresentationController.save_titles_and_notes and an invalid file
with patch('builtins.open') as mocked_open, \
patch('openlp.plugins.presentations.lib.pptviewcontroller.zipfile.is_zipfile') as mocked_is_zf:
mocked_is_zf.return_value = False
mocked_open.filesize = 10
doc = PptviewDocument(self.mock_controller, self.mock_presentation)
doc.file_path = RESOURCE_PATH / 'presentations' / 'test.ppt'
doc.save_titles_and_notes = MagicMock()
# WHEN: reading the titles and notes
doc.create_titles_and_notes()
# THEN:
doc.save_titles_and_notes.assert_called_once_with(None, None)
assert mocked_is_zf.call_count == 1, 'is_zipfile should have been called once'

View File

@ -22,213 +22,196 @@
Functional tests to test the PresentationController and PresentationDocument Functional tests to test the PresentationController and PresentationDocument
classes and related methods. classes and related methods.
""" """
import pytest
from pathlib import Path from pathlib import Path
from unittest import TestCase
from unittest.mock import MagicMock, call, patch from unittest.mock import MagicMock, call, patch
from openlp.core.common.registry import Registry
from openlp.core.common.settings import Settings
from openlp.plugins.presentations.lib.presentationcontroller import PresentationController, PresentationDocument from openlp.plugins.presentations.lib.presentationcontroller import PresentationController, PresentationDocument
FOLDER_TO_PATCH = 'openlp.plugins.presentations.lib.presentationcontroller.PresentationDocument.get_thumbnail_folder' FOLDER_TO_PATCH = 'openlp.plugins.presentations.lib.presentationcontroller.PresentationDocument.get_thumbnail_folder'
class TestPresentationController(TestCase): @pytest.yield_fixture()
def get_thumbnail_folder(settings):
gtf = patch('openlp.plugins.presentations.lib.presentationcontroller.PresentationDocument.get_thumbnail_folder',
return_value=Path())
yield gtf.start()
gtf.stop()
@pytest.yield_fixture()
def create_paths(settings):
c_paths = patch('openlp.plugins.presentations.lib.presentationcontroller.create_paths')
yield c_paths.start()
c_paths.stop()
@pytest.yield_fixture()
def setup(settings):
s_up = patch('openlp.plugins.presentations.lib.presentationcontroller.PresentationDocument._setup')
yield s_up.start()
s_up.stop()
@pytest.fixture()
def presentation(settings, get_thumbnail_folder):
mocked_plugin = MagicMock()
mocked_plugin.settings_section = 'presentations'
return PresentationController(mocked_plugin)
@pytest.fixture()
def document(presentation):
return PresentationDocument(presentation, Path(''))
def test_constructor(presentation):
""" """
Test the PresentationController. Test the Constructor
""" """
def setUp(self): # GIVEN: A mocked plugin
Registry().create()
Registry().register('settings', Settings())
self.get_thumbnail_folder_patcher = \
patch('openlp.plugins.presentations.lib.presentationcontroller.PresentationDocument.get_thumbnail_folder',
return_value=Path())
self.get_thumbnail_folder_patcher.start()
mocked_plugin = MagicMock()
mocked_plugin.settings_section = 'presentations'
self.presentation = PresentationController(mocked_plugin)
self.document = PresentationDocument(self.presentation, '')
def tearDown(self): # WHEN: The PresentationController is created
self.get_thumbnail_folder_patcher.stop()
def test_constructor(self): # THEN: The name of the presentation controller should be correct
""" assert 'PresentationController' == presentation.name, \
Test the Constructor 'The name of the presentation controller should be correct'
"""
# GIVEN: A mocked plugin
# WHEN: The PresentationController is created
# THEN: The name of the presentation controller should be correct
assert 'PresentationController' == self.presentation.name, \
'The name of the presentation controller should be correct'
def test_save_titles_and_notes(self):
"""
Test PresentationDocument.save_titles_and_notes method with two valid lists
"""
# GIVEN: two lists of length==2 and a mocked open and get_thumbnail_folder
with patch('openlp.plugins.presentations.lib.presentationcontroller.Path.write_text') as mocked_write_text, \
patch(FOLDER_TO_PATCH) as mocked_get_thumbnail_folder:
titles = ['uno', 'dos']
notes = ['one', 'two']
# WHEN: calling save_titles_and_notes
mocked_get_thumbnail_folder.return_value = Path('test')
self.document.save_titles_and_notes(titles, notes)
# THEN: the last call to open should have been for slideNotes2.txt
assert mocked_write_text.call_count == 3, 'There should be exactly three files written'
mocked_write_text.assert_has_calls([call('uno\ndos'), call('one'), call('two')])
def test_save_titles_and_notes_with_None(self):
"""
Test PresentationDocument.save_titles_and_notes method with no data
"""
# GIVEN: None and an empty list and a mocked open and get_thumbnail_folder
with patch('builtins.open') as mocked_open, patch(FOLDER_TO_PATCH) as mocked_get_thumbnail_folder:
titles = None
notes = None
# WHEN: calling save_titles_and_notes
mocked_get_thumbnail_folder.return_value = 'test'
self.document.save_titles_and_notes(titles, notes)
# THEN: No file should have been created
assert mocked_open.call_count == 0, 'No file should be created'
def test_get_titles_and_notes(self):
"""
Test PresentationDocument.get_titles_and_notes method
"""
# GIVEN: A mocked open, get_thumbnail_folder and exists
with patch('openlp.plugins.presentations.lib.presentationcontroller.Path.read_text',
return_value='uno\ndos\n') as mocked_read_text, \
patch(FOLDER_TO_PATCH) as mocked_get_thumbnail_folder, \
patch('openlp.plugins.presentations.lib.presentationcontroller.Path.exists') as mocked_exists:
mocked_get_thumbnail_folder.return_value = Path('test')
mocked_exists.return_value = True
# WHEN: calling get_titles_and_notes
result_titles, result_notes = self.document.get_titles_and_notes()
# THEN: it should return two items for the titles and two empty strings for the notes
assert type(result_titles) is list, 'result_titles should be of type list'
assert len(result_titles) == 2, 'There should be two items in the titles'
assert type(result_notes) is list, 'result_notes should be of type list'
assert len(result_notes) == 2, 'There should be two items in the notes'
assert mocked_read_text.call_count == 3, 'Three files should be read'
def test_get_titles_and_notes_with_file_not_found(self):
"""
Test PresentationDocument.get_titles_and_notes method with file not found
"""
# GIVEN: A mocked open, get_thumbnail_folder and exists
with patch('openlp.plugins.presentations.lib.presentationcontroller.Path.read_text') as mocked_read_text, \
patch(FOLDER_TO_PATCH) as mocked_get_thumbnail_folder:
mocked_read_text.side_effect = FileNotFoundError()
mocked_get_thumbnail_folder.return_value = Path('test')
# WHEN: calling get_titles_and_notes
result_titles, result_notes = self.document.get_titles_and_notes()
# THEN: it should return two empty lists
assert isinstance(result_titles, list), 'result_titles should be of type list'
assert len(result_titles) == 0, 'there be no titles'
assert isinstance(result_notes, list), 'result_notes should be a list'
assert len(result_notes) == 0, 'but the list should be empty'
def test_get_titles_and_notes_with_file_error(self):
"""
Test PresentationDocument.get_titles_and_notes method with file errors
"""
# GIVEN: A mocked open, get_thumbnail_folder and exists
with patch('openlp.plugins.presentations.lib.presentationcontroller.Path.read_text') as mocked_read_text, \
patch(FOLDER_TO_PATCH) as mocked_get_thumbnail_folder:
mocked_read_text.side_effect = OSError()
mocked_get_thumbnail_folder.return_value = Path('test')
# WHEN: calling get_titles_and_notes
result_titles, result_notes = self.document.get_titles_and_notes()
# THEN: it should return two empty lists
assert type(result_titles) is list, 'result_titles should be a list'
class TestPresentationDocument(TestCase): def test_save_titles_and_notes(document):
""" """
Test the PresentationDocument Class Test PresentationDocument.save_titles_and_notes method with two valid lists
""" """
def setUp(self): # GIVEN: two lists of length==2 and a mocked open and get_thumbnail_folder
""" with patch('openlp.plugins.presentations.lib.presentationcontroller.Path.write_text') as mocked_write_text, \
Set up the patches and mocks need for all tests. patch(FOLDER_TO_PATCH) as mocked_get_thumbnail_folder:
""" titles = ['uno', 'dos']
Registry().create() notes = ['one', 'two']
self.create_paths_patcher = \
patch('openlp.plugins.presentations.lib.presentationcontroller.create_paths')
self.get_thumbnail_folder_patcher = \
patch('openlp.plugins.presentations.lib.presentationcontroller.PresentationDocument.get_thumbnail_folder')
self._setup_patcher = \
patch('openlp.plugins.presentations.lib.presentationcontroller.PresentationDocument._setup')
self.mock_create_paths = self.create_paths_patcher.start() # WHEN: calling save_titles_and_notes
self.mock_get_thumbnail_folder = self.get_thumbnail_folder_patcher.start() mocked_get_thumbnail_folder.return_value = Path('test')
self.mock_setup = self._setup_patcher.start() document.save_titles_and_notes(titles, notes)
self.mock_controller = MagicMock() # THEN: the last call to open should have been for slideNotes2.txt
assert mocked_write_text.call_count == 3, 'There should be exactly three files written'
mocked_write_text.assert_has_calls([call('uno\ndos'), call('one'), call('two')])
self.mock_get_thumbnail_folder.return_value = Path('returned/path/')
def tearDown(self): def test_save_titles_and_notes_with_none(document):
""" """
Stop the patches Test PresentationDocument.save_titles_and_notes method with no data
""" """
self.create_paths_patcher.stop() # GIVEN: None and an empty list and a mocked open and get_thumbnail_folder
self.get_thumbnail_folder_patcher.stop() with patch('builtins.open') as mocked_open, patch(FOLDER_TO_PATCH) as mocked_get_thumbnail_folder:
self._setup_patcher.stop() titles = None
notes = None
def test_initialise_presentation_document(self): # WHEN: calling save_titles_and_notes
""" mocked_get_thumbnail_folder.return_value = 'test'
Test the PresentationDocument __init__ method when initialising the PresentationDocument Class document.save_titles_and_notes(titles, notes)
"""
# GIVEN: A mocked setup method and mocked controller
self.mock_setup.reset()
# WHEN: Creating an instance of PresentationDocument # THEN: No file should have been created
PresentationDocument(self.mock_controller, 'Name') assert mocked_open.call_count == 0, 'No file should be created'
# THEN: PresentationDocument._setup should have been called with the argument 'Name'
self.mock_setup.assert_called_once_with('Name')
def test_presentation_document_setup(self): def test_get_titles_and_notes(document):
""" """
Test the PresentationDocument _setup method when initialising the PresentationDocument Class Test PresentationDocument.get_titles_and_notes method
""" """
self._setup_patcher.stop() # GIVEN: A mocked open, get_thumbnail_folder and exists
# GIVEN: A mocked controller, patched create_paths and get_thumbnail_folder methods with patch('openlp.plugins.presentations.lib.presentationcontroller.Path.read_text',
return_value='uno\ndos\n') as mocked_read_text, \
patch(FOLDER_TO_PATCH) as mocked_get_thumbnail_folder, \
patch('openlp.plugins.presentations.lib.presentationcontroller.Path.exists') as mocked_exists:
mocked_get_thumbnail_folder.return_value = Path('test')
mocked_exists.return_value = True
# WHEN: Creating an instance of PresentationDocument # WHEN: calling get_titles_and_notes
PresentationDocument(self.mock_controller, 'Name') result_titles, result_notes = document.get_titles_and_notes()
# THEN: create_paths should have been called with 'returned/path/' # THEN: it should return two items for the titles and two empty strings for the notes
self.mock_create_paths.assert_called_once_with(Path('returned', 'path/')) assert type(result_titles) is list, 'result_titles should be of type list'
assert len(result_titles) == 2, 'There should be two items in the titles'
assert type(result_notes) is list, 'result_notes should be of type list'
assert len(result_notes) == 2, 'There should be two items in the notes'
assert mocked_read_text.call_count == 3, 'Three files should be read'
self._setup_patcher.start()
def test_load_presentation(self): def test_get_titles_and_notes_with_file_not_found(document):
""" """
Test the PresentationDocument.load_presentation method. Test PresentationDocument.get_titles_and_notes method with file not found
""" """
# GIVEN: A mocked open, get_thumbnail_folder and exists
with patch('openlp.plugins.presentations.lib.presentationcontroller.Path.read_text') as mocked_read_text, \
patch(FOLDER_TO_PATCH) as mocked_get_thumbnail_folder:
mocked_read_text.side_effect = FileNotFoundError()
mocked_get_thumbnail_folder.return_value = Path('test')
# GIVEN: An instance of PresentationDocument # WHEN: calling get_titles_and_notes
instance = PresentationDocument(self.mock_controller, 'Name') result_titles, result_notes = document.get_titles_and_notes()
# WHEN: Calling load_presentation() # THEN: it should return two empty lists
result = instance.load_presentation() assert isinstance(result_titles, list), 'result_titles should be of type list'
assert len(result_titles) == 0, 'there be no titles'
assert isinstance(result_notes, list), 'result_notes should be a list'
assert len(result_notes) == 0, 'but the list should be empty'
# THEN: load_presentation should return false
assert result is False, "PresentationDocument.load_presentation should return false." def test_get_titles_and_notes_with_file_error(document):
"""
Test PresentationDocument.get_titles_and_notes method with file errors
"""
# GIVEN: A mocked open, get_thumbnail_folder and exists
with patch('openlp.plugins.presentations.lib.presentationcontroller.Path.read_text') as mocked_read_text, \
patch(FOLDER_TO_PATCH) as mocked_get_thumbnail_folder:
mocked_read_text.side_effect = OSError()
mocked_get_thumbnail_folder.return_value = Path('test')
# WHEN: calling get_titles_and_notes
result_titles, result_notes = document.get_titles_and_notes()
# THEN: it should return two empty lists
assert type(result_titles) is list, 'result_titles should be a list'
def test_initialise_presentation_document(setup):
"""
Test the PresentationDocument __init__ method when initialising the PresentationDocument Class
"""
# GIVEN: A mocked setup method and mocked controller
# WHEN: Creating an instance of PresentationDocument
PresentationDocument(MagicMock(), 'Name')
# THEN: PresentationDocument._setup should have been called with the argument 'Name'
setup.assert_called_once_with('Name')
def test_presentation_document_setup(create_paths, get_thumbnail_folder):
"""
Test the PresentationDocument _setup method when initialising the PresentationDocument Class
"""
# GIVEN: A mocked controller, patched create_paths and get_thumbnail_folder methods
get_thumbnail_folder.return_value = Path('returned/path/')
# WHEN: Creating an instance of PresentationDocument
PresentationDocument(MagicMock(), 'Name')
# THEN: create_paths should have been called with 'returned/path/'
create_paths.assert_called_once_with(Path('returned', 'path/'))
def test_load_presentation(get_thumbnail_folder):
"""
Test the PresentationDocument.load_presentation method.
"""
# GIVEN: An instance of PresentationDocument
instance = PresentationDocument(MagicMock(), 'Name')
# WHEN: Calling load_presentation()
result = instance.load_presentation()
# THEN: load_presentation should return false
assert result is False, "PresentationDocument.load_presentation should return false."