Updated tests to pass again.

Found some device dependent problems in the tests of the theme
rendering (when monitor resolution changes, so does font size (in
pixels)). This meant that the tests failed (as they are comparisons
with golden-bitmaps). Have updated the tests to do a more "approximate
comparison", with a low tolerance.  This is slow currently, could do
with optimising.

bzr-revno: 411
This commit is contained in:
Martin Thompson 2009-03-12 20:19:24 +00:00
parent 1d9569236d
commit 90a91aa788
11 changed files with 143 additions and 107 deletions

View File

@ -36,6 +36,7 @@ class OpenLPToolbar(QtGui.QToolBar):
"""
A method to help developers easily add a button to the toolbar.
"""
ButtonIcon = None
if type(icon) is QtGui.QIcon:
ButtonIcon = icon
elif type(icon) is types.StringType:
@ -46,9 +47,10 @@ class OpenLPToolbar(QtGui.QToolBar):
else:
ButtonIcon.addPixmap(QtGui.QPixmap.fromImage(QtGui.QImage(icon)),
QtGui.QIcon.Normal, QtGui.QIcon.Off)
ToolbarButton = self.addAction(ButtonIcon, title)
if tooltip is not None:
ToolbarButton.setToolTip(tooltip)
if ButtonIcon is not None:
ToolbarButton = self.addAction(ButtonIcon, title)
if tooltip is not None:
ToolbarButton.setToolTip(tooltip)
if slot is not None:
QtCore.QObject.connect(ToolbarButton, QtCore.SIGNAL('triggered()'), slot)
self.icons[title]=ButtonIcon

View File

@ -45,7 +45,7 @@ class PluginManager(object):
self.basepath = os.path.abspath(dir)
log.debug("Base path %s ", self.basepath)
self.plugins = []
# this has to happen after the UI is sroted self.find_plugins(dir)
# this has to happen after the UI is sorted self.find_plugins(dir)
log.info("Plugin manager done init")
def find_plugins(self, dir, preview_controller, live_controller): # xxx shouldn't dir come from self.basepath

View File

@ -375,14 +375,19 @@ class Renderer:
print "_get_extent_and_render", [line], tlcorner, dodraw
p=QtGui.QPainter()
p.begin(self._paint)
# use this to scale for rendering in "operators view" xxx
# p.SetUserScale(0.5,0.5)
# 'twould be more efficient to set this once when theme changes
# or p changes
font=QtGui.QFont(self._theme.FontName,
self._theme.FontProportion, # size
QtGui.QFont.Normal, # weight
0)# italic
# to make the unit tests monitor independent, we have to be able to
# specify whether a font proportion is in pixels or points
if self._theme.FontUnits.lower() == "pixels":
print "pixels"
font.setPixelSize(self._theme.FontProportion)
print self._theme.FontName, self._theme.FontProportion
print font.family(), font.pointSize()
p.setFont(font)
if color == None:
p.setPen(self._theme.FontColor)

View File

@ -7,7 +7,8 @@
<BackgroundParameter3/>
<FontName>Tahoma</FontName>
<FontColor>$00007F</FontColor>
<FontProportion>32</FontProportion>
<FontProportion>53</FontProportion>
<FontUnits>pixels</FontUnits>
<Shadow>0</Shadow>
<ShadowColor>$000000</ShadowColor>
<Outline>0</Outline>

View File

@ -19,16 +19,13 @@ import os, sys
mypath=os.path.split(os.path.abspath(__file__))[0]
sys.path.insert(0,(os.path.join(mypath, '..' ,'..', '..')))
from openlp.plugins import MediaManagerItem
from openlp.core.lib import MediaManagerItem
class TestMediaManager:
def setup_class(self):
self.app = QtGui.QApplication([])
logging.info ("App is " + str(self.app))
self.main_window = QtGui.QMainWindow()
self.main_window.resize(200, 600)
# self.StatusBar = QtGui.QStatusBar(self.main_window)
# self.StatusBar.setObjectName("StatusBar")
# self.main_window.setStatusBar(self.StatusBar)
self.MediaManagerDock = QtGui.QDockWidget(self.main_window)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
@ -39,34 +36,29 @@ class TestMediaManager:
icon.addPixmap(QtGui.QPixmap(":/system/system_mediamanager.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.MediaManagerDock.setWindowIcon(icon)
self.MediaManagerDock.setFloating(False)
# self.MediaManagerDock.setObjectName("MediaManagerDock")
self.MediaManagerContents = QtGui.QWidget()
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.MediaManagerContents.sizePolicy().hasHeightForWidth())
self.MediaManagerContents.setSizePolicy(sizePolicy)
# self.MediaManagerContents.setObjectName("MediaManagerContents")
self.MediaManagerLayout = QtGui.QHBoxLayout(self.MediaManagerContents)
self.MediaManagerLayout.setContentsMargins(0, 2, 0, 0)
# self.MediaManagerLayout.setObjectName("MediaManagerLayout")
self.MediaToolBox = QtGui.QToolBox(self.MediaManagerContents)
# self.MediaToolBox.setObjectName("MediaToolBox")
self.MediaManagerDock.setWidget(self.MediaManagerContents)
self.main_window.addDockWidget(QtCore.Qt.DockWidgetArea(1), self.MediaManagerDock)
self.MediaManagerLayout.addWidget(self.MediaToolBox)
def test1(self):
log=logging.getLogger("test1")
log.info("Start")
# i1=MediaManagerItem()
# i2=MediaManagerItem()
i1=MediaManagerItem(self.MediaToolBox)
i2=MediaManagerItem(self.MediaToolBox)
i2.choose_area.text="More Stuff"
log.info("i1"+str(i1))
log.info("i2"+str(i2))
self.MediaToolBox.addItem(i1, i1.icon, "Test1")
self.MediaToolBox.addItem(i2, i2.icon, "Test2")
i1.addToolbar()
i1.addToolbarButton("Test1", "Test1", None)
i2.addToolbar()
i2.addToolbarButton("Test2", "Test2", None)
self.MediaToolBox.setItemText(self.MediaToolBox.indexOf(i1), QtGui.QApplication.translate("main_window", "Item1", None, QtGui.QApplication.UnicodeUTF8))
self.MediaToolBox.setItemText(self.MediaToolBox.indexOf(i2), QtGui.QApplication.translate("main_window", "Item2", None, QtGui.QApplication.UnicodeUTF8))
log.info("Show window")

View File

@ -23,7 +23,9 @@ from openlp.core.pluginmanager import PluginManager
# test the plugin manager with some plugins in the test_plugins directory
class TestPluginManager:
def test_init(self):
p=PluginManager("./testplugins")
self.p=PluginManager("./testplugins")
p=self.p
p.find_plugins('./testplugins', None, None)
assert (len(p.plugins)==2);
# get list of the names of the plugins
names=[plugin.name for plugin in p.plugins]
@ -37,6 +39,8 @@ class TestPluginManager:
assert p.plugins[1].name=="testplugin1"
if __name__=="__main__":
log.debug("Starting")
p=PluginManager("./testplugins")
for plugin in p.plugins:
t=TestPluginManager()
t.test_init()
log.debug("List of plugins found:")
for plugin in t.p.plugins:
log.debug("Plugin %s, name=%s (version=%d)"%(str(plugin), plugin.name, plugin.version))

View File

@ -213,6 +213,7 @@ if __name__=="__main__":
t=TestRender()
t.setup_class()
t.setup_method(None)
t.test_easy()
t.test_splits()
t.teardown_method(None)

View File

@ -21,10 +21,33 @@ import sys
import os
mypath=os.path.split(os.path.abspath(__file__))[0]
sys.path.insert(0,(os.path.join(mypath, '..', '..','..')))
from openlp.theme import Theme
from openlp.core.theme import Theme
from openlp.core import Renderer
from PyQt4 import QtGui, QtCore
def compare_images(goldenim, testim, threshold=0.01):
# easy test first
if goldenim == testim:
return 1
# how close are they? Calculated the sum of absolute differences in
# each channel of each pixel and divide by the number of pixels in the image
# if this sum is < threshold, the images are deemed to be "close enough"
sad=0;
for x in range(goldenim.width()):
for y in range(goldenim.height()):
p1=goldenim.pixel(x,y)
p2=testim.pixel(x,y)
sad += abs((p1&0xFF)-(p2&0xFF))
sad += abs((p1>>8&0xFF)-(p2>>8&0xFF))
sad += abs((p1>>16&0xFF)-(p2>>16&0xFF))
sad /= float(goldenim.width()*goldenim.height())
if (sad < threshold):
return 1
return 0
class TestRenderTheme(TestRender_base):
# {{{ Basics
@ -34,7 +57,7 @@ class TestRenderTheme(TestRender_base):
TestRender_base.setup_method(self, method)
print "Theme setup", method
# print "setup theme"
self.r.set_theme(Theme()) # set "blank" theme
self.r.set_theme(Theme('blank_theme.xml')) # set "blank" theme
self.r.set_text_rectangle(QtCore.QRect(0,0, self.size.width(), self.size.height()))
words="""How sweet the name of Jesus sounds
In a believer's ear!
@ -70,7 +93,7 @@ And drives away his fear.
else:
print "File", goldenfilename, "not found"
return False
if (goldenim == im):
if (compare_images(goldenim, im)):
print name, "Images match"
return True
else:
@ -80,6 +103,7 @@ And drives away his fear.
def test_theme_basic(self):
self.answer=self.r.render_screen(0)
self.bmpname=whoami()
print self.r._theme.FontProportion
print self.answer, self.expected_answer, self.answer==self.expected_answer
# self.msg=self.bmpname
@ -105,14 +129,12 @@ And drives away his fear.
# }}}
# {{{ backgrounds
def test_bg_stretch_y(self):
t=Theme()
t=Theme('blank_theme.xml')
t.BackgroundType = 2
t.BackgroundParameter1 = os.path.join('data_for_tests', "snowsmall.jpg");
t.BackgroundParameter2 = QtGui.QColor(0,0,64);
t.BackgroundParameter3 = 0
t.Name="stretch y"
print t
print "set theme"
self.r.set_theme(t)
print "render"
self.answer=self.r.render_screen(0)
@ -120,7 +142,7 @@ And drives away his fear.
self.bmpname=whoami()
print "fone"
def test_bg_shrink_y(self):
t=Theme()
t=Theme('blank_theme.xml')
t.BackgroundType = 2
t.BackgroundParameter1 = os.path.join('data_for_tests', "snowbig.jpg");
t.BackgroundParameter2 = QtGui.QColor(0,0,64);
@ -131,7 +153,7 @@ And drives away his fear.
self.bmpname=whoami()
def test_bg_stretch_x(self):
t=Theme()
t=Theme('blank_theme.xml')
t.BackgroundType = 2
t.BackgroundParameter1 = os.path.join('data_for_tests', "treessmall.jpg");
t.BackgroundParameter2 = QtGui.QColor(0,0,64);
@ -144,7 +166,7 @@ And drives away his fear.
self.bmpname=whoami()
def test_bg_shrink_x(self):
t=Theme()
t=Theme('blank_theme.xml')
t.BackgroundType = 2
t.BackgroundParameter1 = os.path.join('data_for_tests', "treesbig.jpg");
t.BackgroundParameter2 = QtGui.QColor(0,0,64);
@ -158,7 +180,7 @@ And drives away his fear.
# }}}
# {{{ Vertical alignment
def test_theme_vertical_align_top(self):
t=Theme()
t=Theme('blank_theme.xml')
t.BackgroundType = 0
t.BackgroundParameter1 = QtGui.QColor(0,0,64);
t.VerticalAlign = 0
@ -168,7 +190,7 @@ And drives away his fear.
self.bmpname=whoami()
def test_theme_vertical_align_bot(self):
t=Theme()
t=Theme('blank_theme.xml')
t.BackgroundType = 0
t.BackgroundParameter1 = QtGui.QColor(0,0,64);
t.VerticalAlign = 1
@ -179,7 +201,7 @@ And drives away his fear.
self.bmpname=whoami()
def test_theme_vertical_align_cen(self):
t=Theme()
t=Theme('blank_theme.xml')
t.BackgroundType = 0
t.BackgroundParameter1 = QtGui.QColor(0,0,64);
t.VerticalAlign = 2
@ -191,7 +213,7 @@ And drives away his fear.
# }}}
# {{{ Horzontal alignment
def test_theme_horizontal_align_left(self):
t=Theme()
t=Theme('blank_theme.xml')
t.BackgroundType = 0
t.BackgroundParameter1 = QtGui.QColor(0,0,64);
t.VerticalAlign = 0
@ -202,7 +224,7 @@ And drives away his fear.
self.bmpname=whoami()
def test_theme_horizontal_align_right(self):
t=Theme()
t=Theme('blank_theme.xml')
t.BackgroundType = 0
t.BackgroundParameter1 = QtGui.QColor(0,0,64);
t.VerticalAlign = 0
@ -214,7 +236,7 @@ And drives away his fear.
self.bmpname=whoami()
def test_theme_horizontal_align_centre(self):
t=Theme()
t=Theme('blank_theme.xml')
t.BackgroundType = 0
t.BackgroundParameter1 = QtGui.QColor(0,0,64);
t.VerticalAlign = 0
@ -226,7 +248,7 @@ And drives away his fear.
self.bmpname=whoami()
def test_theme_horizontal_align_left_lyric(self):
t=Theme()
t=Theme('blank_theme.xml')
t.BackgroundType = 0
t.BackgroundParameter1 = QtGui.QColor(0,0,64);
t.VerticalAlign = 0
@ -241,7 +263,8 @@ And drives away his fear.
# }}}
# {{{ Shadows and outlines
def test_theme_shadow_outline(self):
t=Theme()
t=Theme('blank_theme.xml')
t.BackgroundType = 0
t.BackgroundParameter1 = QtGui.QColor(0,0,0);
t.Name="shadow/outline"
@ -259,7 +282,7 @@ And drives away his fear.
self.bmpname=whoami()
# }}}
def test_theme_font(self):
t=Theme()
t=Theme('blank_theme.xml')
t.BackgroundType = 0
t.BackgroundParameter1 = QtGui.QColor(0,0,64);
t.Name="font"
@ -274,5 +297,5 @@ if __name__=="__main__":
t=TestRenderTheme()
t.setup_class()
t.setup_method(None)
t.test_theme_font()
t.test_bg_stretch_y()
t.teardown_method(None)

View File

@ -1,26 +1,8 @@
"""
OpenLP - Open Source Lyrics Projection
Copyright (c) 2008 Raoul Snyman
Portions copyright (c) 2008 Martin Thompson, Tim Bentley
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
"""
import os
import sys
mypath=os.path.split(os.path.abspath(__file__))[0]
sys.path.insert(0,(os.path.join(mypath, '..' ,'..', '..','..')))
sys.path.insert(0,(os.path.join(mypath, '..' ,'..', '..', '..')))
print sys.path
from openlp.core.theme import Theme
@ -38,6 +20,7 @@ def test_read_theme():
assert(t.FontColor == QtGui.QColor(255,255,255))
assert(t.FontName == "Tahoma")
assert(t.FontProportion == 16)
assert(t.FontUnits == "pixels")
assert(t.HorizontalAlign == 2)
assert(t.Name == "openlp.org Packaged Theme")
assert(t.Outline == -1)
@ -45,6 +28,7 @@ def test_read_theme():
assert(t.Shadow == -1)
assert(t.ShadowColor == QtGui.QColor(0,0,1))
assert(t.VerticalAlign == 0)
def test_theme():
# test we create a "blank" theme correctly
t=Theme()
print t
@ -56,16 +40,16 @@ def test_read_theme():
assert(t.FontName == "Arial")
assert(t.FontProportion == 30)
assert(t.HorizontalAlign == 0)
assert(t.FontUnits == "pixels")
assert(t.Name == "BlankStyle")
assert(t.Outline == 0)
assert(t.Shadow == 0)
assert(t.VerticalAlign == 0)
print "Tests passed"
def test_theme():
test_read_theme()
if __name__=="__main__":
test_read_theme()
test_theme()

View File

@ -8,6 +8,7 @@
<FontName>Tahoma</FontName>
<FontColor>clWhite</FontColor>
<FontProportion>16</FontProportion>
<FontUnits>pixels</FontUnits>
<Shadow>-1</Shadow>
<ShadowColor>$00000001</ShadowColor>
<Outline>-1</Outline>

View File

@ -1,30 +1,15 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
"""
OpenLP - Open Source Lyrics Projection
Copyright (c) 2008 Raoul Snyman
Portions copyright (c) 2008 Martin Thompson, Tim Bentley
import platform
ver = platform.python_version()
if ver >= '2.5':
from xml.etree.ElementTree import ElementTree, XML
else:
from elementtree import ElementTree, XML
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
"""
import sys
import os
from PyQt4 import QtGui
sys.path.append(os.path.abspath("./../.."))
from openlp.core.lib import XmlRootClass
DelphiColors={"clRed":0xFF0000,
"clBlack":0x000000,
"clWhite":0xFFFFFF}
blankstylexml=\
'''<?xml version="1.0" encoding="iso-8859-1"?>
@ -37,6 +22,7 @@ blankstylexml=\
<FontName>Arial</FontName>
<FontColor>clWhite</FontColor>
<FontProportion>30</FontProportion>
<FontUnits>pixels</FontUnits>
<Shadow>0</Shadow>
<Outline>0</Outline>
<HorizontalAlign>0</HorizontalAlign>
@ -45,16 +31,12 @@ blankstylexml=\
</Theme>
'''
DelphiColors={"clRed":0xFF0000,
"clBlack":0x000000,
"clWhite":0xFFFFFF}
class Theme(XmlRootClass):
class Theme:
def __init__(self, xmlfile=None):
""" stores the info about a theme
attributes:
name : theme name
BackgroundType : 0 - solid color
1 - gradient color
2 - image
@ -67,10 +49,11 @@ class Theme(XmlRootClass):
for solid - N/A
BackgroundParameter3 : for image - N/A
for gradient - 0 -> vertical, 1 -> horizontal
FontName : name of font to use
FontColor : color for main font
FontProportion : point size of font
FontProportion : size of font
FontUnits : whether size of font is in <pixels> or <points>
Shadow : 0 - no shadow, non-zero use shadow
ShadowColor : color for drop shadow
@ -87,19 +70,59 @@ class Theme(XmlRootClass):
1 - lyrics
"""
# init to defaults
self._setFromXml(blankstylexml, 'Theme')
self._set_from_XML(blankstylexml)
if xmlfile != None:
# init from xmlfile
file=open(xmlfile)
t=''.join(file.readlines()) # read the file and change list to a string
self._setFromXml(t, 'Theme')
self._set_from_XML(t)
def post_tag_hook(self, tag, val):
if DelphiColors.has_key(val):
val=DelphiColors[val]
if (tag.find("Color") > 0 or
(tag.find("BackgroundParameter") == 0 and type(val) == type(0))):
# convert to a QtGui.Color
val= QtGui.QColor((val>>16) & 0xFF, (val>>8)&0xFF, val&0xFF)
def _get_as_string(self):
s=""
keys=dir(self)
keys.sort()
for k in keys:
if k[0:1] != "_":
s+= "_%s_" %(getattr(self,k))
return s
def _set_from_XML(self, xml):
root=ElementTree(element=XML(xml))
iter=root.getiterator()
for element in iter:
if element.tag != "Theme":
t=element.text
# print element.tag, t, type(t)
if type(t) == type(None): # easy!
val=t
if type(t) == type(" "): # strings need special handling to sort the colours out
# print "str",
if t[0] == "$": # might be a hex number
# print "hex",
try:
val=int(t[1:], 16)
except ValueError: # nope
# print "nope",
pass
elif DelphiColors.has_key(t):
# print "colour",
val=DelphiColors[t]
else:
try:
val=int(t)
except ValueError:
val=t
if (element.tag.find("Color") > 0 or
(element.tag.find("BackgroundParameter") == 0 and type(val) == type(0))):
# convert to a wx.Colour
val= QtGui.QColor((val>>16) & 0xFF, (val>>8)&0xFF, val&0xFF)
# print [val]
setattr(self,element.tag, val)
def __str__(self):
s=""
for k in dir(self):
if k[0:1] != "_":
s+= "%30s : %s\n" %(k,getattr(self,k))
return s
return (tag, val)