2013-12-29 19:46:04 +00:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
2019-04-13 13:00:22 +00:00
|
|
|
##########################################################################
|
|
|
|
# OpenLP - Open Source Lyrics Projection #
|
|
|
|
# ---------------------------------------------------------------------- #
|
2020-01-01 02:53:08 +00:00
|
|
|
# Copyright (c) 2008-2020 OpenLP Developers #
|
2019-04-13 13:00:22 +00:00
|
|
|
# ---------------------------------------------------------------------- #
|
|
|
|
# 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/>. #
|
|
|
|
##########################################################################
|
2013-12-29 19:46:04 +00:00
|
|
|
"""
|
|
|
|
This module contains tests for the PdfController
|
|
|
|
"""
|
|
|
|
import os
|
2019-10-18 19:14:22 +00:00
|
|
|
import pytest
|
2019-05-22 06:47:00 +00:00
|
|
|
from pathlib import Path
|
|
|
|
from shutil import rmtree, which
|
2014-03-14 22:08:44 +00:00
|
|
|
from tempfile import mkdtemp
|
2020-07-10 19:45:00 +00:00
|
|
|
from unittest import skipIf
|
2017-04-24 05:17:55 +00:00
|
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
|
2015-11-07 00:49:40 +00:00
|
|
|
from PyQt5 import QtCore, QtGui
|
2013-12-29 19:46:04 +00:00
|
|
|
|
2019-03-25 22:16:45 +00:00
|
|
|
from openlp.core.common import is_macosx, is_linux, is_win
|
2017-10-10 07:08:44 +00:00
|
|
|
from openlp.core.display.screens import ScreenList
|
2017-12-28 08:27:44 +00:00
|
|
|
from openlp.plugins.presentations.lib.pdfcontroller import PdfController, PdfDocument
|
2018-10-02 04:39:42 +00:00
|
|
|
from tests.utils.constants import RESOURCE_PATH
|
|
|
|
|
2013-12-29 19:46:04 +00:00
|
|
|
|
2020-03-05 20:34:08 +00:00
|
|
|
@pytest.yield_fixture()
|
2020-07-21 20:05:59 +00:00
|
|
|
def pdf_env(settings, mock_plugin, mocked_qapp):
|
2020-03-05 20:34:08 +00:00
|
|
|
temp_folder_path = Path(mkdtemp())
|
|
|
|
thumbnail_folder_path = Path(mkdtemp())
|
2020-07-21 20:05:59 +00:00
|
|
|
mocked_screen = MagicMock()
|
|
|
|
mocked_screen.geometry.return_value = QtCore.QRect(0, 0, 1024, 768)
|
|
|
|
mocked_qapp.screens.return_value = [mocked_screen]
|
|
|
|
mocked_qapp.primaryScreen = MagicMock()
|
|
|
|
mocked_qapp.primaryScreen.return_value = mocked_screen
|
|
|
|
ScreenList.create(mocked_qapp)
|
2020-03-05 20:34:08 +00:00
|
|
|
yield settings, mock_plugin, temp_folder_path, thumbnail_folder_path
|
|
|
|
rmtree(thumbnail_folder_path)
|
|
|
|
rmtree(temp_folder_path)
|
|
|
|
|
2013-12-29 19:46:04 +00:00
|
|
|
|
2014-04-03 20:22:10 +00:00
|
|
|
SCREEN = {
|
|
|
|
'primary': False,
|
|
|
|
'number': 1,
|
|
|
|
'size': QtCore.QRect(0, 0, 1024, 768)
|
|
|
|
}
|
2019-10-18 16:54:00 +00:00
|
|
|
IS_CI = 'GITLAB_CI' in os.environ or 'APPVEYOR' in os.environ
|
2020-07-10 19:45:00 +00:00
|
|
|
IS_QT_QPA_PLATFORM_OFFSCREEN = 'QT_QPA_PLATFORM' in os.environ and os.environ['QT_QPA_PLATFORM'] == 'offscreen'
|
2013-12-31 12:15:18 +00:00
|
|
|
|
2014-04-04 20:24:11 +00:00
|
|
|
|
2019-03-25 21:26:48 +00:00
|
|
|
def get_screen_resolution():
|
|
|
|
"""
|
|
|
|
Get the screen resolution
|
|
|
|
"""
|
|
|
|
if is_macosx():
|
2020-07-10 19:45:00 +00:00
|
|
|
if IS_CI:
|
|
|
|
return 1024, 76
|
|
|
|
else:
|
|
|
|
from AppKit import NSScreen
|
|
|
|
screen_size = NSScreen.mainScreen().frame().size
|
|
|
|
return screen_size.width, screen_size.height
|
2019-03-25 22:16:45 +00:00
|
|
|
elif is_win():
|
|
|
|
from win32api import GetSystemMetrics
|
|
|
|
return GetSystemMetrics(0), GetSystemMetrics(1)
|
|
|
|
elif is_linux():
|
2020-03-05 20:34:08 +00:00
|
|
|
if IS_CI:
|
|
|
|
return 1024, 768
|
|
|
|
else:
|
|
|
|
from Xlib.display import Display
|
|
|
|
resolution = Display().screen().root.get_geometry()
|
|
|
|
return resolution.width, resolution.height
|
2019-03-25 21:26:48 +00:00
|
|
|
else:
|
|
|
|
return 1024, 768
|
|
|
|
|
|
|
|
|
2020-03-05 20:34:08 +00:00
|
|
|
def test_constructor(settings, mock_plugin):
|
2013-12-29 19:46:04 +00:00
|
|
|
"""
|
2020-03-05 20:34:08 +00:00
|
|
|
Test the Constructor from the PdfController
|
2013-12-29 19:46:04 +00:00
|
|
|
"""
|
2020-03-05 20:34:08 +00:00
|
|
|
# GIVEN: No presentation controller
|
|
|
|
controller = None
|
|
|
|
|
|
|
|
# WHEN: The presentation controller object is created
|
|
|
|
controller = PdfController(plugin=mock_plugin)
|
|
|
|
|
|
|
|
# THEN: The name of the presentation controller should be correct
|
|
|
|
assert 'Pdf' == controller.name, 'The name of the presentation controller should be correct'
|
|
|
|
|
|
|
|
|
|
|
|
def load_pdf(exe_path, pdf_env):
|
|
|
|
"""
|
|
|
|
Test loading a Pdf using the PdfController
|
|
|
|
"""
|
|
|
|
# GIVEN: A Pdf-file
|
|
|
|
test_file_path = RESOURCE_PATH / 'presentations' / 'pdf_test1.pdf'
|
|
|
|
|
|
|
|
# WHEN: The Pdf is loaded
|
|
|
|
settings = pdf_env[0]
|
|
|
|
mock_plugin = pdf_env[1]
|
|
|
|
temp_folder_path = pdf_env[2]
|
|
|
|
thumbnail_folder_path = pdf_env[3]
|
|
|
|
settings.setValue('presentations/pdf_program', exe_path)
|
|
|
|
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()
|
|
|
|
|
|
|
|
# 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.'
|
|
|
|
|
|
|
|
|
2020-07-10 19:45:00 +00:00
|
|
|
@skipIf(IS_QT_QPA_PLATFORM_OFFSCREEN, 'This test fails when QT_QPA_PLATFORM is set to "offscreen".')
|
2020-03-05 20:34:08 +00:00
|
|
|
def load_pdf_pictures(exe_path, pdf_env):
|
|
|
|
"""
|
|
|
|
Test loading a Pdf and check the generated pictures' size
|
|
|
|
"""
|
|
|
|
# GIVEN: A Pdf-file
|
|
|
|
test_file_path = RESOURCE_PATH / 'presentations' / 'pdf_test1.pdf'
|
|
|
|
|
|
|
|
# WHEN: The Pdf is loaded
|
2020-06-06 16:05:36 +00:00
|
|
|
settings = pdf_env[0]
|
2020-03-05 20:34:08 +00:00
|
|
|
mock_plugin = pdf_env[1]
|
|
|
|
temp_folder_path = pdf_env[2]
|
|
|
|
thumbnail_folder_path = pdf_env[3]
|
2020-06-06 16:05:36 +00:00
|
|
|
settings.setValue('presentations/pdf_program', exe_path)
|
2020-03-05 20:34:08 +00:00
|
|
|
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()
|
|
|
|
|
|
|
|
# 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.'
|
|
|
|
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
|
|
|
|
if controller.gsbin:
|
|
|
|
assert 1076 == image.height(), 'The height should be 1076'
|
|
|
|
assert 760 == image.width(), 'The width should be 760'
|
|
|
|
else:
|
|
|
|
width, height = get_screen_resolution()
|
|
|
|
# Calculate the width of the PDF based on the aspect ratio of the PDF
|
|
|
|
width = int(round(height * 0.70703125, 0))
|
|
|
|
assert image.height() == height, 'The height should be {height}'.format(height=height)
|
|
|
|
assert image.width() == width, 'The width should be {width}'.format(width=width)
|
|
|
|
|
|
|
|
|
|
|
|
def test_load_pdf(pdf_env):
|
|
|
|
"""
|
|
|
|
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:
|
|
|
|
load_pdf(exe_path, pdf_env)
|
|
|
|
load_pdf_pictures(exe_path, pdf_env)
|
|
|
|
|
|
|
|
|
2020-03-08 21:45:42 +00:00
|
|
|
def test_loading_pdf_using_pymupdf(pdf_env):
|
2020-03-05 20:34:08 +00:00
|
|
|
try:
|
|
|
|
import fitz # noqa: F401
|
|
|
|
except ImportError:
|
|
|
|
pytest.skip('PyMuPDF is not installed')
|
|
|
|
|
2020-03-08 21:45:42 +00:00
|
|
|
load_pdf(None, pdf_env)
|
|
|
|
load_pdf_pictures(None, pdf_env)
|
2020-03-05 20:34:08 +00:00
|
|
|
|
|
|
|
|
|
|
|
@patch('openlp.plugins.presentations.lib.pdfcontroller.check_binary_exists')
|
|
|
|
def test_process_check_binary_mudraw(mocked_check_binary_exists):
|
|
|
|
"""
|
|
|
|
Test that the correct output from mudraw is detected
|
|
|
|
"""
|
|
|
|
# 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
|
|
|
|
ret = PdfController.process_check_binary('test')
|
|
|
|
|
|
|
|
# THEN: mudraw should be detected
|
|
|
|
assert 'mudraw' == ret, 'mudraw should have been detected'
|
|
|
|
|
|
|
|
|
|
|
|
@patch('openlp.plugins.presentations.lib.pdfcontroller.check_binary_exists')
|
|
|
|
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
|
|
|
|
|
|
|
|
# WHEN: Calling process_check_binary
|
|
|
|
ret = PdfController.process_check_binary('test')
|
|
|
|
|
|
|
|
# THEN: mutool should be detected
|
|
|
|
assert 'mutool' == ret, 'mutool should have been detected'
|
|
|
|
|
|
|
|
|
|
|
|
@patch('openlp.plugins.presentations.lib.pdfcontroller.check_binary_exists')
|
|
|
|
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'
|