More tests

This commit is contained in:
Raoul Snyman 2016-11-05 14:17:36 +02:00
parent b9cf077b36
commit 5fe84e4130
2 changed files with 527 additions and 40 deletions

View File

@ -1,3 +1,24 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2016 OpenLP Developers #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
""" """
This module runs a Pyro4 server using LibreOffice's version of Python This module runs a Pyro4 server using LibreOffice's version of Python
""" """
@ -54,6 +75,41 @@ class LibreOfficeServer(object):
self._document = None self._document = None
self._presentation = None self._presentation = None
self._process = None self._process = None
self._manager = None
def _create_property(self, name, value):
"""
Create an OOo style property object which are passed into some Uno methods.
"""
log.debug('create property')
property_object = PropertyValue()
property_object.Name = name
property_object.Value = value
return property_object
def _get_text_from_page(self, slide_no, text_type=TextType.SlideText):
"""
Return any text extracted from the presentation page.
:param slide_no: The slide the notes are required for, starting at 1
:param notes: A boolean. If set the method searches the notes of the slide.
:param text_type: A TextType. Enumeration of the types of supported text.
"""
text = ''
if TextType.Title <= text_type <= TextType.Notes:
pages = self._document.getDrawPages()
if 0 < slide_no <= pages.getCount():
page = pages.getByIndex(slide_no - 1)
if text_type == TextType.Notes:
page = page.getNotesPage()
for index in range(page.getCount()):
shape = page.getByIndex(index)
shape_type = shape.getShapeType()
if shape.supportsService('com.sun.star.drawing.Text'):
# if they requested title, make sure it is the title
if text_type != TextType.Title or shape_type == 'com.sun.star.presentation.TitleTextShape':
text += shape.getString() + '\n'
return text
def start_process(self): def start_process(self):
""" """
@ -93,40 +149,6 @@ class LibreOfficeServer(object):
except Exception as e: except Exception as e:
log.warning('Failed to get UNO desktop') log.warning('Failed to get UNO desktop')
def _create_property(self, name, value):
"""
Create an OOo style property object which are passed into some Uno methods.
"""
log.debug('create property')
property_object = PropertyValue()
property_object.Name = name
property_object.Value = value
return property_object
def _get_text_from_page(self, slide_no, text_type=TextType.SlideText):
"""
Return any text extracted from the presentation page.
:param slide_no: The slide the notes are required for, starting at 1
:param notes: A boolean. If set the method searches the notes of the slide.
:param text_type: A TextType. Enumeration of the types of supported text.
"""
text = ''
if TextType.Title <= text_type <= TextType.Notes:
pages = self._document.getDrawPages()
if 0 < slide_no <= pages.getCount():
page = pages.getByIndex(slide_no - 1)
if text_type == TextType.Notes:
page = page.getNotesPage()
for index in range(page.getCount()):
shape = page.getByIndex(index)
shape_type = shape.getShapeType()
if shape.supportsService('com.sun.star.drawing.Text'):
# if they requested title, make sure it is the title
if text_type != TextType.Title or shape_type == 'com.sun.star.presentation.TitleTextShape':
text += shape.getString() + '\n'
return text
def has_desktop(self): def has_desktop(self):
""" """
Say if we have a desktop object Say if we have a desktop object
@ -206,8 +228,7 @@ class LibreOfficeServer(object):
def get_titles_and_notes(self): def get_titles_and_notes(self):
""" """
Writes the list of titles (one per slide) to 'titles.txt' and the notes to 'slideNotes[x].txt' Extract the titles and the notes from the slides.
in the thumbnails directory
""" """
titles = [] titles = []
notes = [] notes = []
@ -222,8 +243,7 @@ class LibreOfficeServer(object):
def close_presentation(self): def close_presentation(self):
""" """
Close presentation and clean up objects. Triggered by new object being added to SlideController or OpenLP being Close presentation and clean up objects.
shutdown.
""" """
log.debug('close Presentation LibreOffice') log.debug('close Presentation LibreOffice')
if self._document: if self._document:

View File

@ -22,8 +22,6 @@
""" """
Functional tests to test the LibreOffice Pyro server Functional tests to test the LibreOffice Pyro server
""" """
from unittest import TestCase
from openlp.plugins.presentations.lib.libreofficeserver import LibreOfficeServer, TextType from openlp.plugins.presentations.lib.libreofficeserver import LibreOfficeServer, TextType
from tests.functional import MagicMock, patch, call from tests.functional import MagicMock, patch, call
@ -44,6 +42,7 @@ def test_constructor():
assert server._presentation is None assert server._presentation is None
assert server._process is None assert server._process is None
@patch('openlp.plugins.presentations.lib.libreofficeserver.Popen') @patch('openlp.plugins.presentations.lib.libreofficeserver.Popen')
def test_start_process(MockedPopen): def test_start_process(MockedPopen):
""" """
@ -69,6 +68,23 @@ def test_start_process(MockedPopen):
]) ])
assert server._process is mocked_process assert server._process is mocked_process
@patch('openlp.plugins.presentations.lib.libreofficeserver.uno')
def test_setup_desktop_already_has_desktop(mocked_uno):
"""
Test that setup_desktop() exits early when there's already a desktop
"""
# GIVEN: A LibreOfficeServer instance
server = LibreOfficeServer()
server._desktop = MagicMock()
# WHEN: setup_desktop() is called
server.setup_desktop()
# THEN: setup_desktop() exits early
assert server._manager is None
@patch('openlp.plugins.presentations.lib.libreofficeserver.uno') @patch('openlp.plugins.presentations.lib.libreofficeserver.uno')
def test_setup_desktop(mocked_uno): def test_setup_desktop(mocked_uno):
""" """
@ -104,6 +120,7 @@ def test_setup_desktop(mocked_uno):
assert server._manager is MockedServiceManager assert server._manager is MockedServiceManager
assert server._desktop is mocked_desktop assert server._desktop is mocked_desktop
@patch('openlp.plugins.presentations.lib.libreofficeserver.PropertyValue') @patch('openlp.plugins.presentations.lib.libreofficeserver.PropertyValue')
def test_create_property(MockedPropertyValue): def test_create_property(MockedPropertyValue):
""" """
@ -121,6 +138,7 @@ def test_create_property(MockedPropertyValue):
assert prop.Name == name assert prop.Name == name
assert prop.Value == value assert prop.Value == value
def test_get_text_from_page_slide_text(): def test_get_text_from_page_slide_text():
""" """
Test that the _get_text_from_page() method gives us nothing for slide text Test that the _get_text_from_page() method gives us nothing for slide text
@ -147,6 +165,7 @@ def test_get_text_from_page_slide_text():
# THE: The text is correct # THE: The text is correct
assert text == 'Page Text\n' assert text == 'Page Text\n'
def test_get_text_from_page_title(): def test_get_text_from_page_title():
""" """
Test that the _get_text_from_page() method gives us the text from the titles Test that the _get_text_from_page() method gives us the text from the titles
@ -173,6 +192,7 @@ def test_get_text_from_page_title():
# THEN: The text should be correct # THEN: The text should be correct
assert text == 'Page Title\n' assert text == 'Page Title\n'
def test_get_text_from_page_notes(): def test_get_text_from_page_notes():
""" """
Test that the _get_text_from_page() method gives us the text from the notes Test that the _get_text_from_page() method gives us the text from the notes
@ -201,6 +221,7 @@ def test_get_text_from_page_notes():
# THEN: The text should be correct # THEN: The text should be correct
assert text == 'Page Notes\n' assert text == 'Page Notes\n'
def test_has_desktop_no_desktop(): def test_has_desktop_no_desktop():
""" """
Test the has_desktop() method when there's no desktop Test the has_desktop() method when there's no desktop
@ -214,6 +235,7 @@ def test_has_desktop_no_desktop():
# THEN: The result should be False # THEN: The result should be False
assert result is False assert result is False
def test_has_desktop(): def test_has_desktop():
""" """
Test the has_desktop() method Test the has_desktop() method
@ -228,6 +250,7 @@ def test_has_desktop():
# THEN: The result should be True # THEN: The result should be True
assert result is True assert result is True
def test_shutdown(): def test_shutdown():
""" """
Test the shutdown method Test the shutdown method
@ -266,6 +289,7 @@ def test_shutdown():
mocked_desktop.terminate.assert_called_once_with() mocked_desktop.terminate.assert_called_once_with()
server._process.kill.assert_called_once_with() server._process.kill.assert_called_once_with()
@patch('openlp.plugins.presentations.lib.libreofficeserver.uno') @patch('openlp.plugins.presentations.lib.libreofficeserver.uno')
def test_load_presentation(mocked_uno): def test_load_presentation(mocked_uno):
""" """
@ -300,6 +324,7 @@ def test_load_presentation(mocked_uno):
assert server._presentation.Display == screen_number assert server._presentation.Display == screen_number
assert server._control is None assert server._control is None
@patch('openlp.plugins.presentations.lib.libreofficeserver.uno') @patch('openlp.plugins.presentations.lib.libreofficeserver.uno')
@patch('openlp.plugins.presentations.lib.libreofficeserver.os') @patch('openlp.plugins.presentations.lib.libreofficeserver.os')
def test_extract_thumbnails(mocked_os, mocked_uno): def test_extract_thumbnails(mocked_os, mocked_uno):
@ -340,3 +365,445 @@ def test_extract_thumbnails(mocked_os, mocked_uno):
[call('/tmp/1.png', ({'FilterName': 'impress_png_Export'},)), [call('/tmp/1.png', ({'FilterName': 'impress_png_Export'},)),
call('/tmp/2.png', ({'FilterName': 'impress_png_Export'},))] call('/tmp/2.png', ({'FilterName': 'impress_png_Export'},))]
assert thumbnails == ['/tmp/1.png', '/tmp/2.png'] assert thumbnails == ['/tmp/1.png', '/tmp/2.png']
def test_get_titles_and_notes():
"""
Test the get_titles_and_notes() method
"""
# GIVEN: A LibreOfficeServer object and a bunch of mocks
server = LibreOfficeServer()
mocked_document = MagicMock()
mocked_pages = MagicMock()
server._document = mocked_document
mocked_document.getDrawPages.return_value = mocked_pages
mocked_pages.getCount.return_value = 2
# WHEN: get_titles_and_notes() is called
with patch.object(server, '_get_text_from_page') as mocked_get_text_from_page:
mocked_get_text_from_page.side_effect = [
'OpenLP on Mac OS X',
'',
'',
'Installing is a drag-and-drop affair'
]
titles, notes = server.get_titles_and_notes()
# THEN: The right calls are made and the right stuff returned
mocked_document.getDrawPages.assert_called_once_with()
mocked_pages.getCount.assert_called_once_with()
assert mocked_get_text_from_page.call_count == 4
expected_calls = [
call(1, TextType.Title), call(1, TextType.Notes),
call(2, TextType.Title), call(2, TextType.Notes),
]
assert mocked_get_text_from_page.call_args_list == expected_calls
assert titles == ['OpenLP on Mac OS X\n', '\n'], titles
assert notes == [' ', 'Installing is a drag-and-drop affair'], notes
def test_close_presentation():
"""
Test that closing the presentation cleans things up correctly
"""
# GIVEN: A LibreOfficeServer instance and a bunch of mocks
server = LibreOfficeServer()
mocked_document = MagicMock()
mocked_presentation = MagicMock()
server._document = mocked_document
server._presentation = mocked_presentation
# WHEN: close_presentation() is called
server.close_presentation()
# THEN: The presentation and document should be closed
mocked_presentation.end.assert_called_once_with()
mocked_document.dispose.assert_called_once_with()
assert server._document is None
assert server._presentation is None
def test_is_loaded_no_objects():
"""
Test the is_loaded() method when there's no document or presentation
"""
# GIVEN: A LibreOfficeServer instance and a bunch of mocks
server = LibreOfficeServer()
# WHEN: The is_loaded() method is called
result = server.is_loaded()
# THEN: The result should be false
assert result is False
def test_is_loaded_no_presentation():
"""
Test the is_loaded() method when there's no presentation
"""
# GIVEN: A LibreOfficeServer instance and a bunch of mocks
server = LibreOfficeServer()
mocked_document = MagicMock()
server._document = mocked_document
server._presentation = MagicMock()
mocked_document.getPresentation.return_value = None
# WHEN: The is_loaded() method is called
result = server.is_loaded()
# THEN: The result should be false
assert result is False
mocked_document.getPresentation.assert_called_once_with()
def test_is_loaded():
"""
Test the is_loaded() method
"""
# GIVEN: A LibreOfficeServer instance and a bunch of mocks
server = LibreOfficeServer()
mocked_document = MagicMock()
mocked_presentation = MagicMock()
server._document = mocked_document
server._presentation = mocked_presentation
mocked_document.getPresentation.return_value = mocked_presentation
# WHEN: The is_loaded() method is called
result = server.is_loaded()
# THEN: The result should be false
assert result is True
mocked_document.getPresentation.assert_called_once_with()
def test_is_active_not_loaded():
"""
Test is_active() when is_loaded() returns False
"""
# GIVEN: A LibreOfficeServer instance and a bunch of mocks
server = LibreOfficeServer()
# WHEN: is_active() is called with is_loaded() returns False
result = server.is_loaded()
# THEN: It should have returned False
assert result is False
def test_is_active_no_control():
"""
Test is_active() when is_loaded() returns True but there's no control
"""
# GIVEN: A LibreOfficeServer instance and a bunch of mocks
server = LibreOfficeServer()
# WHEN: is_active() is called with is_loaded() returns False
with patch.object(server, 'is_loaded') as mocked_is_loaded:
mocked_is_loaded.return_value = True
result = server.is_active()
# THEN: The result should be False
assert result is False
mocked_is_loaded.assert_called_once_with()
def test_is_active():
"""
Test is_active()
"""
# GIVEN: A LibreOfficeServer instance and a bunch of mocks
server = LibreOfficeServer()
mocked_control = MagicMock()
server._control = mocked_control
mocked_control.isRunning.return_value = True
# WHEN: is_active() is called with is_loaded() returns False
with patch.object(server, 'is_loaded') as mocked_is_loaded:
mocked_is_loaded.return_value = True
result = server.is_active()
# THEN: The result should be False
assert result is True
mocked_is_loaded.assert_called_once_with()
mocked_control.isRunning.assert_called_once_with()
def test_unblank_screen():
"""
Test the unblank_screen() method
"""
# GIVEN: A LibreOfficeServer instance and a bunch of mocks
server = LibreOfficeServer()
mocked_control = MagicMock()
server._control = mocked_control
# WHEN: unblank_screen() is run
server.unblank_screen()
# THEN: The resume method should have been called
mocked_control.resume.assert_called_once_with()
def test_blank_screen():
"""
Test the blank_screen() method
"""
# GIVEN: A LibreOfficeServer instance and a bunch of mocks
server = LibreOfficeServer()
mocked_control = MagicMock()
server._control = mocked_control
# WHEN: blank_screen() is run
server.blank_screen()
# THEN: The resume method should have been called
mocked_control.blankScreen.assert_called_once_with(0)
def test_is_blank_no_control():
"""
Test the is_blank() method when there's no control
"""
# GIVEN: A LibreOfficeServer instance and a bunch of mocks
server = LibreOfficeServer()
# WHEN: is_blank() is called
result = server.is_blank()
# THEN: It should have returned False
assert result is False
def test_is_blank_control_is_running():
"""
Test the is_blank() method when the control is running
"""
# GIVEN: A LibreOfficeServer instance and a bunch of mocks
server = LibreOfficeServer()
mocked_control = MagicMock()
server._control = mocked_control
mocked_control.isRunning.return_value = True
mocked_control.isPaused.return_value = True
# WHEN: is_blank() is called
result = server.is_blank()
# THEN: It should have returned False
assert result is True
mocked_control.isRunning.assert_called_once_with()
mocked_control.isPaused.assert_called_once_with()
def test_stop_presentation():
"""
Test the stop_presentation() method
"""
# GIVEN: A LibreOfficeServer instance and a mocked presentation
server = LibreOfficeServer()
mocked_presentation = MagicMock()
mocked_control = MagicMock()
server._presentation = mocked_presentation
server._control = mocked_control
# WHEN: stop_presentation() is called
server.stop_presentation()
# THEN: The presentation is ended and the control is removed
mocked_presentation.end.assert_called_once_with()
assert server._control is None
@patch('openlp.plugins.presentations.lib.libreofficeserver.time.sleep')
def test_start_presentation_no_control(mocked_sleep):
"""
Test the start_presentation() method when there's no control
"""
# GIVEN: A LibreOfficeServer instance and some mocks
server = LibreOfficeServer()
mocked_control = MagicMock()
mocked_document = MagicMock()
mocked_presentation = MagicMock()
mocked_controller = MagicMock()
mocked_frame = MagicMock()
mocked_window = MagicMock()
server._document = mocked_document
server._presentation = mocked_presentation
mocked_document.getCurrentController.return_value = mocked_controller
mocked_controller.getFrame.return_value = mocked_frame
mocked_frame.getContainerWindow.return_value = mocked_window
mocked_presentation.getController.side_effect = [None, mocked_control]
# WHEN: start_presentation() is called
server.start_presentation()
# THEN: The slide number should be correct
mocked_document.getCurrentController.assert_called_once_with()
mocked_controller.getFrame.assert_called_once_with()
mocked_frame.getContainerWindow.assert_called_once_with()
mocked_presentation.start.assert_called_once_with()
assert mocked_presentation.getController.call_count == 2
mocked_sleep.assert_called_once_with(0.1)
assert mocked_window.setVisible.call_args_list == [call(True), call(False)]
assert server._control is mocked_control
def test_start_presentation():
"""
Test the start_presentation() method when there's a control
"""
# GIVEN: A LibreOfficeServer instance and some mocks
server = LibreOfficeServer()
mocked_control = MagicMock()
server._control = mocked_control
# WHEN: start_presentation() is called
with patch.object(server, 'goto_slide') as mocked_goto_slide:
server.start_presentation()
# THEN: The control should have been activated and the first slide selected
mocked_control.activate.assert_called_once_with()
mocked_goto_slide.assert_called_once_with(1)
def test_get_slide_number():
"""
Test the get_slide_number() method
"""
# GIVEN: A LibreOfficeServer instance and some mocks
server = LibreOfficeServer()
mocked_control = MagicMock()
mocked_control.getCurrentSlideIndex.return_value = 3
server._control = mocked_control
# WHEN: get_slide_number() is called
result = server.get_slide_number()
# THEN: The slide number should be correct
assert result == 4
def test_get_slide_count():
"""
Test the get_slide_count() method
"""
# GIVEN: A LibreOfficeServer instance and some mocks
server = LibreOfficeServer()
mocked_document = MagicMock()
mocked_pages = MagicMock()
server._document = mocked_document
mocked_document.getDrawPages.return_value = mocked_pages
mocked_pages.getCount.return_value = 2
# WHEN: get_slide_count() is called
result = server.get_slide_count()
# THEN: The slide count should be correct
assert result == 2
def test_goto_slide():
"""
Test the goto_slide() method
"""
# GIVEN: A LibreOfficeServer instance and some mocks
server = LibreOfficeServer()
mocked_control = MagicMock()
server._control = mocked_control
# WHEN: goto_slide() is called
result = server.goto_slide(1)
# THEN: The slide number should be correct
mocked_control.gotoSlideIndex.assert_called_once_with(0)
@patch('openlp.plugins.presentations.lib.libreofficeserver.time.sleep')
def test_next_step_when_paused(mocked_sleep):
"""
Test the next_step() method when paused
"""
# GIVEN: A LibreOfficeServer instance and a mocked control
server = LibreOfficeServer()
mocked_control = MagicMock()
server._control = mocked_control
mocked_control.isPaused.side_effect = [False, True]
# WHEN: next_step() is called
result = server.next_step()
# THEN: The correct call should be made
mocked_control.gotoNextEffect.assert_called_once_with()
mocked_sleep.assert_called_once_with(0.1)
assert mocked_control.isPaused.call_count == 2
mocked_control.gotoPreviousEffect.assert_called_once_with()
@patch('openlp.plugins.presentations.lib.libreofficeserver.time.sleep')
def test_next_step(mocked_sleep):
"""
Test the next_step() method when paused
"""
# GIVEN: A LibreOfficeServer instance and a mocked control
server = LibreOfficeServer()
mocked_control = MagicMock()
server._control = mocked_control
mocked_control.isPaused.side_effect = [True, True]
# WHEN: next_step() is called
result = server.next_step()
# THEN: The correct call should be made
mocked_control.gotoNextEffect.assert_called_once_with()
mocked_sleep.assert_called_once_with(0.1)
assert mocked_control.isPaused.call_count == 1
assert mocked_control.gotoPreviousEffect.call_count == 0
def test_previous_step():
"""
Test the previous_step() method
"""
# GIVEN: A LibreOfficeServer instance and a mocked control
server = LibreOfficeServer()
mocked_control = MagicMock()
server._control = mocked_control
# WHEN: previous_step() is called
result = server.previous_step()
# THEN: The correct call should be made
mocked_control.gotoPreviousEffect.assert_called_once_with()
def test_get_slide_text():
"""
Test the get_slide_text() method
"""
# GIVEN: A LibreOfficeServer instance
server = LibreOfficeServer()
# WHEN: get_slide_text() is called for a particular slide
with patch.object(server, '_get_text_from_page') as mocked_get_text_from_page:
mocked_get_text_from_page.return_value = 'OpenLP on Mac OS X'
result = server.get_slide_text(5)
# THEN: The text should be returned
mocked_get_text_from_page.assert_called_once_with(5)
assert result == 'OpenLP on Mac OS X'
def test_get_slide_notes():
"""
Test the get_slide_notes() method
"""
# GIVEN: A LibreOfficeServer instance
server = LibreOfficeServer()
# WHEN: get_slide_notes() is called for a particular slide
with patch.object(server, '_get_text_from_page') as mocked_get_text_from_page:
mocked_get_text_from_page.return_value = 'Installing is a drag-and-drop affair'
result = server.get_slide_notes(3)
# THEN: The text should be returned
mocked_get_text_from_page.assert_called_once_with(3, TextType.Notes)
assert result == 'Installing is a drag-and-drop affair'