offapi/UnoApi_offapi.mk                                    |    3 
 offapi/org/libreoffice/embindtest/ExplicitConstructors.idl |   21 +++
 offapi/org/libreoffice/embindtest/ImplicitConstructor.idl  |   18 ++
 offapi/org/libreoffice/embindtest/XArgumentStore.idl       |   18 ++
 pyuno/PythonTest_pyuno_pytests_embindtest.mk               |    1 
 pyuno/qa/pytests/serviceconstructors.py                    |   82 +++++++++++++
 uitest/uitest/test.py                                      |    7 -
 unotest/Library_embindtest.mk                              |    1 
 unotest/source/embindtest/embindtest.component             |    6 
 unotest/source/embindtest/serviceconstructors.cxx          |   62 +++++++++
 10 files changed, 215 insertions(+), 4 deletions(-)

New commits:
commit 7930a07d76d7708b69372fd54133675af0e0ec9e
Author:     Neil Roberts <[email protected]>
AuthorDate: Tue Feb 10 20:50:10 2026 +0100
Commit:     Stephan Bergmann <[email protected]>
CommitDate: Wed Mar 4 13:53:16 2026 +0100

    uitest: Use the new service constructors to create the Toolkit
    
    Instead of explicitly calling createInstance we can use the implicit
    service constructor on the Toolkit type for a slightly nicer way to
    construct it.
    
    Change-Id: Ia06000afc0cde27209966854704ca8dd61375adf
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/199106
    Reviewed-by: Stephan Bergmann <[email protected]>
    Tested-by: Jenkins

diff --git a/uitest/uitest/test.py b/uitest/uitest/test.py
index 98ede61a6cf1..42fb2abb575c 100644
--- a/uitest/uitest/test.py
+++ b/uitest/uitest/test.py
@@ -12,6 +12,7 @@ from contextlib import contextmanager
 from uitest.uihelper.common import get_state_as_dict, select_by_text
 
 from com.sun.star.uno import RuntimeException
+from com.sun.star.awt import Toolkit
 
 from libreoffice.uno.eventlistener import EventListener
 from libreoffice.uno.propertyvalue import mkPropertyValues
@@ -197,8 +198,7 @@ class UITest(object):
                     self._xUITest.executeCommandForProvider(".uno:CloseWin", 
frame)
                 # Closing the window will happen asynchronously on the main 
thread so let’s wait
                 # until the close actually completes.
-                xToolkit = 
self._xContext.ServiceManager.createInstance('com.sun.star.awt.Toolkit')
-                xToolkit.waitUntilAllIdlesDispatched()
+                Toolkit.create(self._xContext).waitUntilAllIdlesDispatched()
 
     # Calls UITest.close_doc at exit
     @contextmanager
@@ -301,8 +301,7 @@ class UITest(object):
                 # execute_dialog_through_command will end up dispatching the 
command asynchronously
                 # on the main thread. The Base code seems to have a few race 
conditions so to avoid
                 # that let’s wait to make sure the close completes before 
continuing
-                xToolkit = 
self._xContext.ServiceManager.createInstance('com.sun.star.awt.Toolkit')
-                xToolkit.waitUntilAllIdlesDispatched()
+                Toolkit.create(self._xContext).waitUntilAllIdlesDispatched()
             else:
                 self._xUITest.executeCommand(".uno:CloseDoc")
         frames = desktop.getFrames()
commit 2cd17a11484904845dc386315026882c72696543
Author:     Neil Roberts <[email protected]>
AuthorDate: Tue Feb 10 22:52:57 2026 +0100
Commit:     Stephan Bergmann <[email protected]>
CommitDate: Wed Mar 4 13:53:05 2026 +0100

    Add a PythonTest for service constructors in pyuno
    
    This leverages the existing framework for embindtest to add interfaces
    and services to test with. Hopefully that means the tests will run on
    the CI without ending up in the final release builds because they are
    only enabled with --enable-embindtest-uno.
    
    Change-Id: Idd394e616ad14943cecd60bf3a3e228d93166e34
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/199105
    Tested-by: Jenkins
    Reviewed-by: Stephan Bergmann <[email protected]>

diff --git a/offapi/UnoApi_offapi.mk b/offapi/UnoApi_offapi.mk
index eabe9d8a07e7..356e97893dcc 100644
--- a/offapi/UnoApi_offapi.mk
+++ b/offapi/UnoApi_offapi.mk
@@ -4391,10 +4391,13 @@ $(eval $(call 
gb_UnoApi_add_idlfiles,offapi,org/libreoffice/embindtest, \
     Constants \
     Enum \
     Exception \
+    ExplicitConstructors \
+    ImplicitConstructor \
     Struct \
     StructLong \
     StructString \
     Template \
+    XArgumentStore \
     XAttributes \
     XTest \
 ))
diff --git a/offapi/org/libreoffice/embindtest/ExplicitConstructors.idl 
b/offapi/org/libreoffice/embindtest/ExplicitConstructors.idl
new file mode 100644
index 000000000000..d2034f2660cd
--- /dev/null
+++ b/offapi/org/libreoffice/embindtest/ExplicitConstructors.idl
@@ -0,0 +1,21 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * 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/.
+ */
+
+module org { module libreoffice { module embindtest {
+
+service ExplicitConstructors: org::libreoffice::embindtest::XArgumentStore
+{
+    multipleArguments([in] long a, [in] string b, [in] float c);
+    interfaceArgument([in] com::sun::star::uno::XInterface a);
+    restArgument([in] any... rest);
+};
+
+}; }; };
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/offapi/org/libreoffice/embindtest/ImplicitConstructor.idl 
b/offapi/org/libreoffice/embindtest/ImplicitConstructor.idl
new file mode 100644
index 000000000000..56067fa0c5ec
--- /dev/null
+++ b/offapi/org/libreoffice/embindtest/ImplicitConstructor.idl
@@ -0,0 +1,18 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * 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/.
+ */
+
+module org { module libreoffice { module embindtest {
+
+// This should make an implicit default constructor that only takes
+// the component context as an argument.
+service ImplicitConstructor: org::libreoffice::embindtest::XArgumentStore;
+
+}; }; };
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/offapi/org/libreoffice/embindtest/XArgumentStore.idl 
b/offapi/org/libreoffice/embindtest/XArgumentStore.idl
new file mode 100644
index 000000000000..22cfd1ec5eb2
--- /dev/null
+++ b/offapi/org/libreoffice/embindtest/XArgumentStore.idl
@@ -0,0 +1,18 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * 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/.
+ */
+
+module org { module libreoffice { module embindtest {
+
+interface XArgumentStore {
+    sequence<any> getArguments();
+};
+
+}; }; };
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/pyuno/PythonTest_pyuno_pytests_embindtest.mk 
b/pyuno/PythonTest_pyuno_pytests_embindtest.mk
index 8f8341f7c50e..053b05f1d2d1 100644
--- a/pyuno/PythonTest_pyuno_pytests_embindtest.mk
+++ b/pyuno/PythonTest_pyuno_pytests_embindtest.mk
@@ -11,6 +11,7 @@ $(eval $(call 
gb_PythonTest_PythonTest,pyuno_pytests_embindtest))
 
 $(eval $(call 
gb_PythonTest_add_modules,pyuno_pytests_embindtest,$(SRCDIR)/pyuno/qa/pytests, \
     embindtest \
+    serviceconstructors \
 ))
 
 # vim: set noet sw=4 ts=4:
diff --git a/pyuno/qa/pytests/serviceconstructors.py 
b/pyuno/qa/pytests/serviceconstructors.py
new file mode 100644
index 000000000000..ce742ef9b54f
--- /dev/null
+++ b/pyuno/qa/pytests/serviceconstructors.py
@@ -0,0 +1,82 @@
+# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-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 unittest
+import org.libreoffice.unotest
+from org.libreoffice.embindtest import ImplicitConstructor
+from org.libreoffice.embindtest import ExplicitConstructors
+from com.sun.star.script import CannotConvertException
+
+class ServiceConstructorsTest(unittest.TestCase):
+    def test_implicit_constructor(self):
+        ctx = org.libreoffice.unotest.pyuno.getComponentContext()
+        obj = ImplicitConstructor.create(ctx)
+        self.assertEqual(obj.getArguments(), tuple())
+
+    def test_multiple_arguments(self):
+        ctx = org.libreoffice.unotest.pyuno.getComponentContext()
+        obj = ExplicitConstructors.multipleArguments(ctx, 42, " is half of ", 
84.0)
+        self.assertEqual(obj.getArguments(), (42, " is half of ", 84.0))
+
+    def test_interface_argument(self):
+        ctx = org.libreoffice.unotest.pyuno.getComponentContext()
+        obj = ExplicitConstructors.interfaceArgument(ctx, ctx)
+        self.assertEqual(obj.getArguments(), (ctx, ))
+
+        # None should be coerced into a null reference even though
+        # normally it’s supposed to represent the void type
+        obj = ExplicitConstructors.interfaceArgument(ctx, None)
+        self.assertEqual(obj.getArguments(), (None, ))
+
+    def test_rest_arguments(self):
+        ctx = org.libreoffice.unotest.pyuno.getComponentContext()
+
+        obj = ExplicitConstructors.restArgument(ctx)
+        self.assertEqual(obj.getArguments(), tuple())
+
+        obj = ExplicitConstructors.restArgument(ctx, 1, 2, "buckle my shoe")
+        self.assertEqual(obj.getArguments(), (1, 2, "buckle my shoe"))
+
+    def test_invalid_arguments(self):
+        ctx = org.libreoffice.unotest.pyuno.getComponentContext()
+
+        with self.assertRaises(AttributeError) as cm:
+            ImplicitConstructor.create()
+        self.assertEqual(str(cm.exception),
+                         
"org.libreoffice.embindtest.ImplicitConstructor::create "
+                         "requires 1 argument")
+
+        with self.assertRaises(AttributeError) as cm:
+            ExplicitConstructors.interfaceArgument()
+        self.assertEqual(str(cm.exception),
+                         
"org.libreoffice.embindtest.ExplicitConstructors::interfaceArgument "
+                         "requires 2 arguments")
+
+        with self.assertRaises(AttributeError) as cm:
+            ExplicitConstructors.interfaceArgument(1, 2, 3)
+        self.assertEqual(str(cm.exception),
+                         
"org.libreoffice.embindtest.ExplicitConstructors::interfaceArgument "
+                         "requires 2 arguments")
+
+        with self.assertRaises(AttributeError) as cm:
+            ExplicitConstructors.restArgument()
+        self.assertEqual(str(cm.exception),
+                         
"org.libreoffice.embindtest.ExplicitConstructors::restArgument "
+                         "requires at least 1 argument")
+
+        with self.assertRaises(AttributeError) as cm:
+            ImplicitConstructor.create(True)
+        self.assertEqual(str(cm.exception),
+                         "First argument to a service constructor must be an "
+                         "XComponentContext")
+
+        with self.assertRaises(CannotConvertException):
+            ExplicitConstructors.interfaceArgument(ctx, 12)
+
+# vim: set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/unotest/Library_embindtest.mk b/unotest/Library_embindtest.mk
index 439b711c3a2c..4c7a92f4d5c1 100644
--- a/unotest/Library_embindtest.mk
+++ b/unotest/Library_embindtest.mk
@@ -11,6 +11,7 @@ $(eval $(call gb_Library_Library,embindtest))
 
 $(eval $(call gb_Library_add_exception_objects,embindtest, \
     unotest/source/embindtest/embindtest \
+    unotest/source/embindtest/serviceconstructors \
 ))
 
 $(eval $(call 
gb_Library_set_componentfile,embindtest,unotest/source/embindtest/embindtest,services))
diff --git a/unotest/source/embindtest/embindtest.component 
b/unotest/source/embindtest/embindtest.component
index 9391811ce2d0..30bdc5c3f68f 100644
--- a/unotest/source/embindtest/embindtest.component
+++ b/unotest/source/embindtest/embindtest.component
@@ -22,4 +22,10 @@
             name="org.libreoffice.comp.embindtest.Test">
         <service name="org.libreoffice.embindtest.Test"/>
     </implementation>
+    <implementation
+            
constructor="org_libreoffice_comp_embindtest_Constructors_get_implementation"
+            name="org.libreoffice.comp.embindtest.Constructors">
+        <service name="org.libreoffice.embindtest.ImplicitConstructor"/>
+        <service name="org.libreoffice.embindtest.ExplicitConstructors"/>
+    </implementation>
 </component>
diff --git a/unotest/source/embindtest/serviceconstructors.cxx 
b/unotest/source/embindtest/serviceconstructors.cxx
new file mode 100644
index 000000000000..c5feed409840
--- /dev/null
+++ b/unotest/source/embindtest/serviceconstructors.cxx
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * 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/.
+ */
+
+#include <sal/config.h>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <org/libreoffice/embindtest/XArgumentStore.hpp>
+
+namespace com::sun::star::uno
+{
+class XComponentContext;
+}
+
+namespace
+{
+class ConstructorsTest : public 
cppu::WeakImplHelper<org::libreoffice::embindtest::XArgumentStore,
+                                                     css::lang::XServiceInfo>
+{
+public:
+    explicit ConstructorsTest(css::uno::Sequence<css::uno::Any> const& args)
+        : m_aArgs(args)
+    {
+    }
+
+    OUString SAL_CALL getImplementationName() override
+    {
+        return u"org.libreoffice.comp.embindtest.Constructors"_ustr;
+    }
+
+    sal_Bool SAL_CALL supportsService(OUString const& ServiceName) override
+    {
+        return cppu::supportsService(this, ServiceName);
+    }
+
+    css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override
+    {
+        return { u"org.libreoffice.embindtest.ImplicitConstructor"_ustr,
+                 u"org.libreoffice.embindtest.ExplicitConstructors"_ustr };
+    }
+
+    css::uno::Sequence<css::uno::Any> SAL_CALL getArguments() override { 
return m_aArgs; }
+
+private:
+    css::uno::Sequence<css::uno::Any> m_aArgs;
+};
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+org_libreoffice_comp_embindtest_Constructors_get_implementation(
+    css::uno::XComponentContext*, css::uno::Sequence<css::uno::Any> const& 
args)
+{
+    return cppu::acquire(new ConstructorsTest(args));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */

Reply via email to