set up python unit test infrastructure

Extract boostraping code from convwatch.py to unotest.py. Use python builtin
unittest module as unit test framework. Specify the unit test modules in make
file. Another option would be to use discover mode of unittest module.

Add __pycache__ to global .gitignore to keep the source directory clean.
Another option would be to deliver the unit tests to workdir prior to test
execution.

Currently only system python3 is supported.

Change-Id: I2692817673f786e950e1176a17c7675f989755b6
Reviewed-on: https://gerrit.libreoffice.org/3214
Reviewed-by: David Ostrovsky <David.Ostrovsky@gmx.de>
Tested-by: David Ostrovsky <David.Ostrovsky@gmx.de>
This commit is contained in:
David Ostrovsky 2013-03-30 22:10:48 +01:00 committed by David Ostrovsky
parent d64b5cc1c3
commit 0e68bac852
11 changed files with 421 additions and 0 deletions

1
.gitignore vendored
View file

@ -75,5 +75,6 @@
/solenv/gdb/libreoffice/*.pyo
/solenv/gdb/libreoffice/util/*.pyo
/moz/zipped/*.zip
__pycache__

View file

@ -0,0 +1,83 @@
# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
#
# This file is part of the LibreOffice project.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# PythonTest class
# TODO: FixMe problem with internal python:
# Fatal Python error: Py_Initialize: Unable to get the locale encoding
#gb_Python_EXE := $(call gb_Executable_get_command,python)
gb_Python_EXE := python3
gb_PythonTest_COMMAND := $(gb_Python_EXE) -m unittest
.PHONY : $(call gb_PythonTest_get_clean_target,%)
$(call gb_PythonTest_get_clean_target,%) :
$(call gb_Helper_abbreviate_dirs,\
rm -f $@ $@.log)
ifneq ($(DISABLE_PYTHON),TRUE)
.PHONY : $(call gb_PythonTest_get_target,%)
$(call gb_PythonTest_get_target,%) :
$(call gb_Output_announce,$*,$(true),PYT,2)
$(call gb_Helper_abbreviate_dirs,\
mkdir -p $(dir $(call gb_PythonTest_get_target,$*)) && \
(PYTHONPATH=$(SRCDIR)/unotest/source/python:$(DEVINSTALLDIR)/opt/program \
SOFFICE_BIN=$(DEVINSTALLDIR)/opt/program/soffice \
URE_BOOTSTRAP=file://$(DEVINSTALLDIR)/opt/program/fundamentalrc \
$(gb_PythonTest_COMMAND) \
$(CLASSES) > $@.log 2>&1 || \
(cat $@.log \
&& false)))
$(CLEAN_CMD)
define gb_PythonTest_PythonTest
$(call gb_PythonTest_get_target,$(1)) : T_CP :=
$(call gb_PythonTest_get_target,$(1)) : CLASSES :=
$(eval $(call gb_Module_register_target,$(call gb_PythonTest_get_target,$(1)),$(call gb_PythonTest_get_clean_target,$(1))))
$(call gb_Helper_make_userfriendly_targets,$(1),PythonTest)
endef
define gb_PythonTest_add_classes
$(call gb_PythonTest_get_target,$(1)) : CLASSES += $(2)
endef
define gb_PythonTest_add_class
$(call gb_PythonTest_add_classes,$(1),$(2))
endef
define gb_PythonTest_use_customtarget
$(call gb_PythonTest_get_target,$(1)) : $(call gb_CustomTarget_get_workdir,$(2))
endef
else # DISABLE_PYTHON
.PHONY : $(call gb_PythonTest_get_target,$(1))
$(call gb_PythonTest_get_target,%) :
$(call gb_Output_announce,$* (skipped - no PythonTest),$(true),PYT,2)
@true
define gb_PythonTest_PythonTest
$(eval $(call gb_Module_register_target,$(call gb_PythonTest_get_target,$(1)),$(call gb_PythonTest_get_clean_target,$(1))))
$(call gb_Helper_make_userfriendly_targets,$(1),PythonTest)
endef
gb_PythonTest_add_classes :=
gb_PythonTest_add_class :=
gb_JunitTest_use_customtarget :=
endif # DISABLE_PYTHON
# vim: set noet sw=4:

View file

@ -148,6 +148,7 @@ gb_JavaClassSet_get_target = $(WORKDIR)/JavaClassSet/$(1)/done
gb_JunitTest_get_classsetname = JunitTest/$(1)
gb_JunitTest_get_target = $(WORKDIR)/JunitTest/$(1)/done
gb_JunitTest_get_userdir = $(WORKDIR)/JunitTest/$(1)/user
gb_PythonTest_get_target = $(WORKDIR)/PythonTest/$(1)/done
gb_LinkTarget_get_external_headers_target = $(WORKDIR)/ExternalHeaders/$(1)
gb_LinkTarget_get_headers_target = $(WORKDIR)/Headers/$(1)
gb_LinkTarget_get_target = $(WORKDIR)/LinkTarget/$(1)
@ -290,6 +291,7 @@ $(eval $(call gb_Helper_make_clean_targets,\
Pagein \
PrecompiledHeader \
Pyuno \
PythonTest \
Rdb \
ResTarget \
ScpMergeTarget \

View file

@ -313,6 +313,7 @@ include $(foreach class, \
Pagein \
PrecompiledHeaders \
Pyuno \
PythonTest \
Rdb \
CppunitTest \
Jar \

View file

@ -66,4 +66,13 @@ $(eval $(call gb_Module_add_subsequentcheck_targets,sw,\
))
endif
# TODO: FixMe restrict to system python
ifneq ($(DISABLE_PYTHON),TRUE)
ifeq ($(SYSTEM_PYTHON),YES)
$(eval $(call gb_Module_add_subsequentcheck_targets,sw,\
PythonTest_sw_unoapi \
))
endif
endif
# vim: set noet sw=4 ts=4:

View file

@ -0,0 +1,17 @@
# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
#
# This file is part of the LibreOffice project.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
$(eval $(call gb_PythonTest_PythonTest,sw_unoapi))
$(eval $(call gb_PythonTest_add_classes,sw_unoapi,\
$(SRCDIR)/sw/qa/unoapi/python/set_expression.py \
$(SRCDIR)/sw/qa/unoapi/python/get_expression.py \
))
# vim: set noet sw=4 ts=4:

View file

@ -0,0 +1,53 @@
import unittest
from org.libreoffice.unotest import UnoConnection
class TestGetExpression(unittest.TestCase):
_unoCon = None
_xDoc = None
@classmethod
def setUpClass(cls):
cls._unoCon = UnoConnection({})
cls._unoCon.setUp()
cls._xDoc = cls._unoCon.openEmptyWriterDoc()
@classmethod
def tearDownClass(cls):
cls._unoCon.tearDown()
def test_get_expression(self):
self.__class__._unoCon.checkProperties(
self.__class__._xDoc.createInstance("com.sun.star.text.textfield.GetExpression"),
{"Content": "foo",
"CurrentPresentation": "bar",
"NumberFormat": 0,
"IsShowFormula": False,
"SubType": 0,
"VariableSubtype": 1,
"IsFixedLanguage": False,
},
self
)
# property 'Value' is read only?
@unittest.expectedFailure
def test_get_expression_veto_read_only(self):
self.__class__._unoCon.checkProperties(
self.__class__._xDoc.createInstance("com.sun.star.text.textfield.GetExpression"),
{"Value": 0.0},
self
)
# property 'NumberingType' is unknown?
@unittest.expectedFailure
def test_get_expression_unknown_property(self):
self.__class__._unoCon.checkProperties(
self.__class__._xDoc.createInstance("com.sun.star.text.textfield.GetExpression"),
{"NumberingType": 0},
self
)
if __name__ == '__main__':
unittest.main()

View file

@ -0,0 +1,40 @@
import unittest
from org.libreoffice.unotest import UnoConnection
#@unittest.skip("that seems to work")
class TestSetExpresion(unittest.TestCase):
_unoCon = None
_xDoc = None
@classmethod
def setUpClass(cls):
cls._unoCon = UnoConnection({})
cls._unoCon.setUp()
cls._xDoc = cls._unoCon.openEmptyWriterDoc()
@classmethod
def tearDownClass(cls):
cls._unoCon.tearDown()
def test_set_expression(self):
self.__class__._unoCon.checkProperties(
self.__class__._xDoc.createInstance("com.sun.star.text.textfield.SetExpression"),
{"NumberingType": 0,
"Content": "foo",
"CurrentPresentation": "bar",
"NumberFormat": 0,
"NumberingType": 0,
"IsShowFormula": False,
"IsInput": False,
"IsVisible": True,
"SequenceValue": 0,
"SubType": 0,
"Value": 1.0,
"IsFixedLanguage": False
},
self
)
if __name__ == '__main__':
unittest.main()

View file

View file

@ -0,0 +1,215 @@
# -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
#
# This file is part of the LibreOffice project.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
import subprocess
import time
import uuid
import argparse
import os
try:
import pyuno
import uno
except ImportError:
print("pyuno not found: try to set PYTHONPATH and URE_BOOTSTRAP variables")
print("PYTHONPATH=/installation/opt/program")
print("URE_BOOTSTRAP=file:///installation/opt/program/fundamentalrc")
raise
try:
from com.sun.star.document import XDocumentEventListener
except ImportError:
print("UNO API class not found: try to set URE_BOOTSTRAP variable")
print("URE_BOOTSTRAP=file:///installation/opt/program/fundamentalrc")
raise
### utilities ###
def mkPropertyValue(name, value):
return uno.createUnoStruct("com.sun.star.beans.PropertyValue", name, 0, value, 0)
### UNO utilities ###
class OfficeConnection(object):
def __init__(self, args):
self.args = args
self.soffice = None
self.xContext = None
self.channel = None
def setUp(self):
try:
self.verbose = self.args["verbose"]
except KeyError:
self.verbose = False
try:
prog = self.args["programm"]
except KeyError:
prog = os.getenv("SOFFICE_BIN")
if not (prog):
raise Exception("SOFFICE_BIN must be set")
channel = "pipe,name=pytest" + str(uuid.uuid1())
try:
userdir = self.args["userdir"]
except KeyError:
userdir = "file:///tmp"
if not(userdir.startswith("file://")):
raise Exception("--userdir must be file URL")
self.soffice = self.bootstrap(prog, userdir, channel)
return self.connect(channel)
def bootstrap(self, soffice, userdir, channel):
argv = [ soffice, "--accept=" + channel + ";urp",
"-env:UserInstallation=" + userdir,
"--quickstart=no", "--nofirststartwizard",
"--norestore", "--nologo", "--headless"]
if "--valgrind" in self.args:
argv.append("--valgrind")
if self.verbose:
print ("starting LibreOffice with channel: ", channel)
return subprocess.Popen(argv)
def connect(self, channel):
xLocalContext = uno.getComponentContext()
xUnoResolver = xLocalContext.ServiceManager.createInstanceWithContext(
"com.sun.star.bridge.UnoUrlResolver", xLocalContext)
url = ("uno:%s;urp;StarOffice.ComponentContext" % channel)
if self.verbose:
print("Connecting to: ", url)
while True:
try:
self.xContext = xUnoResolver.resolve(url)
return self.xContext
# except com.sun.star.connection.NoConnectException
except pyuno.getClass("com.sun.star.connection.NoConnectException"):
print("WARN: NoConnectException: sleeping...")
time.sleep(1)
def tearDown(self):
if self.soffice:
if self.xContext:
try:
if self.verbose:
print("tearDown: calling terminate()...")
xMgr = self.xContext.ServiceManager
xDesktop = xMgr.createInstanceWithContext(
"com.sun.star.frame.Desktop", self.xContext)
xDesktop.terminate()
if self.verbose:
print("...done")
# except com.sun.star.lang.DisposedException:
except pyuno.getClass("com.sun.star.beans.UnknownPropertyException"):
print("caught UnknownPropertyException")
pass # ignore, also means disposed
except pyuno.getClass("com.sun.star.lang.DisposedException"):
print("caught DisposedException")
pass # ignore
else:
self.soffice.terminate()
ret = self.soffice.wait()
self.xContext = None
self.socket = None
self.soffice = None
# WTF 255 return value?
# if ret != 0:
# raise Exception("Exit status indicates failure: " + str(ret))
# return ret
def getContext(self):
return self.xContext
class UnoConnection:
def __init__(self, args):
self.args = args
self.connection = None
def getContext(self):
return self.connection.xContext
def getDoc(self):
return self.xDoc
def setUp(self):
conn = OfficeConnection(self.args)
conn.setUp()
self.connection = conn
def openEmptyWriterDoc(self):
assert(self.connection)
smgr = self.getContext().ServiceManager
desktop = smgr.createInstanceWithContext("com.sun.star.frame.Desktop", self.getContext())
props = [("Hidden", True), ("ReadOnly", False)]
loadProps = tuple([mkPropertyValue(name, value) for (name, value) in props])
self.xDoc = desktop.loadComponentFromURL("private:factory/swriter", "_blank", 0, loadProps)
return self.xDoc
def checkProperties(self, obj, dict, test):
for k,v in dict.items():
obj.setPropertyValue(k, v)
value = obj.getPropertyValue(k)
test.assertEqual(value, v)
def postTest(self):
assert(self.connection)
def tearDown(self):
if self.connection:
try:
self.connection.tearDown()
finally:
self.connection = None
def simpleInvoke(connection, test):
try:
connection.preTest()
test.run(connection.getContext())
finally:
connection.postTest()
def retryInvoke(connection, test):
tries = 5
while tries > 0:
try:
tries -= 1
try:
connection.preTest()
test.run(connection.getContext())
return
finally:
connection.postTest()
except KeyboardInterrupt:
raise # Ctrl+C should work
except:
print("retryInvoke: caught exception")
raise Exception("FAILED retryInvoke")
def runConnectionTests(connection, invoker, tests):
try:
connection.setUp()
for test in tests:
invoker(connection, test)
finally:
connection.tearDown()
### tests ###
if __name__ == "__main__":
parser = argparse.ArgumentParser("Help utilities for testing LibreOffice")
group = parser.add_mutually_exclusive_group()
group.add_argument("-v", "--verbose", help="increase output verbosity", action="store_true")
#parser.add_argument("p", type=str, help="programm name")
args = parser.parse_args()
if args.verbose:
verbose = True
con = PersistentConnection({"verbose" : args.verbose})
print("starting soffice ... ", end="")
con.setUp()
print("done")
con.get
print ("shutting down ... ", end="")
con.tearDown()
print("done")
# vim:set shiftwidth=4 softtabstop=4 expandtab: