1 # -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*-
3 # This file is part of the LibreOffice project.
5 # This Source Code Form is subject to the terms of the Mozilla Public
6 # License, v. 2.0. If a copy of the MPL was not distributed with this
7 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
24 print("pyuno not found: try to set PYTHONPATH and URE_BOOTSTRAP variables")
25 print("to something like:")
26 print(" PYTHONPATH=/installation/opt/program")
27 print(" URE_BOOTSTRAP=file:///installation/opt/program/fundamentalrc")
31 from com
.sun
.star
.document
import XDocumentEventListener
33 print("UNO API class not found: try to set URE_BOOTSTRAP variable")
34 print("to something like:")
35 print(" URE_BOOTSTRAP=file:///installation/opt/program/fundamentalrc")
40 def mkPropertyValue(name
, value
):
41 return uno
.createUnoStruct("com.sun.star.beans.PropertyValue", name
, 0, value
, 0)
43 def mkPropertyValues(**kwargs
):
44 '''mkPropertyValues(Name=Value, Name=Value,...) -> (PropertyValue, PropertyValue,...)
45 ex. : mkPropertyValues(Hidden=True, ReadOnly=False)'''
46 from com
.sun
.star
.beans
import PropertyValue
47 return tuple(PropertyValue(k
,0,kwargs
[k
],0) for k
in kwargs
)
49 def fileUrlToSystemPath(url
):
50 return pyuno
.fileUrlToSystemPath(url
)
52 def systemPathToFileUrl(systemPath
):
53 return pyuno
.systemPathToFileUrl(systemPath
)
57 class OfficeConnection(object):
59 def __init__(self
, args
):
67 self
.verbose
= self
.args
["verbose"]
71 prog
= self
.args
["program"]
73 prog
= os
.getenv("SOFFICE_BIN")
75 raise Exception("SOFFICE_BIN must be set")
76 channel
= "pipe,name=pytest" + str(uuid
.uuid1())
78 userdir
= self
.args
["userdir"]
80 userdir
= "file:///tmp"
81 if not(userdir
.startswith("file://")):
82 raise Exception("--userdir must be file URL")
83 self
.soffice
= self
.bootstrap(prog
, userdir
, channel
)
84 return self
.connect(channel
)
86 def bootstrap(self
, soffice
, userdir
, channel
):
87 argv
= [ soffice
, "--accept=" + channel
+ ";urp",
88 "-env:UserInstallation=" + userdir
,
90 "--norestore", "--nologo", "--headless"]
91 if "--valgrind" in self
.args
:
92 argv
.append("--valgrind")
94 print ("starting LibreOffice with channel: ", channel
)
95 return subprocess
.Popen(argv
)
97 def connect(self
, channel
):
98 xLocalContext
= uno
.getComponentContext()
99 xUnoResolver
= xLocalContext
.ServiceManager
.createInstanceWithContext(
100 "com.sun.star.bridge.UnoUrlResolver", xLocalContext
)
101 url
= ("uno:%s;urp;StarOffice.ComponentContext" % channel
)
103 print("Connecting to: ", url
)
106 self
.xContext
= xUnoResolver
.resolve(url
)
108 # except com.sun.star.connection.NoConnectException
109 except pyuno
.getClass("com.sun.star.connection.NoConnectException"):
110 print("WARN: NoConnectException: sleeping...")
118 print("tearDown: calling terminate()...")
119 xMgr
= self
.xContext
.ServiceManager
120 xDesktop
= xMgr
.createInstanceWithContext(
121 "com.sun.star.frame.Desktop", self
.xContext
)
125 # except com.sun.star.lang.DisposedException:
126 except pyuno
.getClass("com.sun.star.beans.UnknownPropertyException"):
127 print("caught UnknownPropertyException")
128 pass # ignore, also means disposed
129 except pyuno
.getClass("com.sun.star.lang.DisposedException"):
130 print("caught DisposedException")
133 self
.soffice
.terminate()
134 ret
= self
.soffice
.wait()
139 raise Exception("Exit status indicates failure: " + str(ret
))
141 def getContext(self
):
144 class UnoRemoteConnection
:
145 def __init__(self
, args
):
147 self
.connection
= None
148 def getContext(self
):
149 return self
.connection
.xContext
153 conn
= OfficeConnection(self
.args
)
155 self
.connection
= conn
156 def openEmptyWriterDoc(self
):
157 assert(self
.connection
)
158 smgr
= self
.getContext().ServiceManager
159 desktop
= smgr
.createInstanceWithContext("com.sun.star.frame.Desktop", self
.getContext())
160 props
= [("Hidden", True), ("ReadOnly", False)]
161 loadProps
= tuple([mkPropertyValue(name
, value
) for (name
, value
) in props
])
162 self
.xDoc
= desktop
.loadComponentFromURL("private:factory/swriter", "_blank", 0, loadProps
)
165 def checkProperties(self
, obj
, dict, test
):
166 for k
,v
in dict.items():
167 obj
.setPropertyValue(k
, v
)
168 value
= obj
.getPropertyValue(k
)
169 test
.assertEqual(value
, v
)
172 assert(self
.connection
)
176 self
.connection
.tearDown()
178 self
.connection
= None
183 def getContext(self
):
188 self
.xContext
= pyuno
.getComponentContext()
191 pyuno
.private_initTestEnvironment()
194 def openEmptyWriterDoc(self
):
195 return self
.openEmptyDoc("private:factory/swriter")
197 def openEmptyCalcDoc(self
):
198 return self
.openEmptyDoc("private:factory/scalc")
200 def openEmptyDoc(self
, url
, bHidden
= True, bReadOnly
= False):
201 props
= [("Hidden", bHidden
), ("ReadOnly", bReadOnly
)]
202 return self
.__openDocFromURL
(url
, props
)
204 def openTemplateFromTDOC(self
, file):
205 return self
.openDocFromTDOC(file, True)
207 def openDocFromTDOC(self
, file, asTemplate
= False):
208 path
= makeCopyFromTDOC(file)
209 return self
.openDocFromAbsolutePath(path
, asTemplate
)
211 def openDocFromAbsolutePath(self
, file, asTemplate
= False):
212 return self
.openDocFromURL(pathlib
.Path(file).as_uri(), asTemplate
)
214 def openDocFromURL(self
, url
, asTemplate
= False):
215 props
= [("Hidden", True), ("ReadOnly", False), ("AsTemplate", asTemplate
)]
216 return self
.__openDocFromURL
(url
, props
)
218 def __openDocFromURL(self
, url
, props
):
219 assert(self
.xContext
)
220 smgr
= self
.getContext().ServiceManager
221 desktop
= smgr
.createInstanceWithContext("com.sun.star.frame.Desktop", self
.getContext())
222 loadProps
= tuple([mkPropertyValue(name
, value
) for (name
, value
) in props
])
223 self
.xDoc
= desktop
.loadComponentFromURL(url
, "_blank", 0, loadProps
)
227 def checkProperties(self
, obj
, dict, test
):
228 for k
,v
in dict.items():
229 obj
.setPropertyValue(k
, v
)
230 value
= obj
.getPropertyValue(k
)
231 test
.assertEqual(value
, v
)
233 def setProperties(self
, obj
, dict):
234 for k
,v
in dict.items():
235 obj
.setPropertyValue(k
, v
)
238 assert(self
.xContext
)
240 if hasattr(self
, 'xDoc'):
242 self
.xDoc
.close(True)
243 # HACK in case self.xDoc holds a UNO proxy to an SwXTextDocument (whose dtor calls
244 # Application::GetSolarMutex via sw::UnoImplPtrDeleter), which would potentially only be
245 # garbage-collected after VCL has already been deinitialized:
248 def simpleInvoke(connection
, test
):
251 test
.run(connection
.getContext())
253 connection
.postTest()
255 def retryInvoke(connection
, test
):
262 test
.run(connection
.getContext())
265 connection
.postTest()
266 except KeyboardInterrupt:
267 raise # Ctrl+C should work
269 print("retryInvoke: caught exception")
270 raise Exception("FAILED retryInvoke")
272 def runConnectionTests(connection
, invoker
, tests
):
276 invoker(connection
, test
)
278 connection
.tearDown()
280 def makeCopyFromTDOC(file):
281 src
= os
.getenv("TDOC")
282 assert(src
is not None)
283 src
= os
.path
.join(src
, file)
284 dst
= os
.getenv("TestUserDir")
285 assert(dst
is not None)
286 uri
= urllib
.parse
.urlparse(dst
)
287 assert(uri
.scheme
.casefold() == "file")
288 assert(uri
.netloc
== "" or uri
.netloc
.casefold() == "localhost")
289 assert(uri
.params
== "")
290 assert(uri
.query
== "")
291 assert(uri
.fragment
== "")
292 dst
= urllib
.request
.url2pathname(uri
.path
)
293 dst
= os
.path
.join(dst
, "tmp", file)
294 os
.makedirs(os
.path
.dirname(dst
), exist_ok
=True)
297 except FileNotFoundError
:
299 shutil
.copyfile(src
, dst
)
304 if __name__
== "__main__":
305 parser
= argparse
.ArgumentParser("Help utilities for testing LibreOffice")
306 group
= parser
.add_mutually_exclusive_group()
307 group
.add_argument("-v", "--verbose", help="increase output verbosity", action
="store_true")
308 #parser.add_argument("p", type=str, help="program name")
309 args
= parser
.parse_args()
312 from uitest
.libreoffice
.connection
import PersistentConnection
313 con
= PersistentConnection({"verbose" : args
.verbose
})
314 print("starting soffice ... ", end
="")
318 print ("shutting down ... ", end
="")
322 # vim: set shiftwidth=4 softtabstop=4 expandtab: