Add a unit test that constructs every service-based singleton via class name

The idea is to check that all of the class names match a singleton
declared in a component somewhere and that they return an object that
implements the advertised interface. Otherwise the generated getter for
the singleton will fail with a runtime exception.

Change-Id: I1352e7392e33e9182962e6279fcb62cf3b58352a
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/200056
Reviewed-by: Neil Roberts <bpeeluk@yahoo.co.uk>
Tested-by: Jenkins
This commit is contained in:
Neil Roberts
2026-02-23 16:39:43 +01:00
parent 99c0fcc777
commit 26e03a6571
3 changed files with 138 additions and 0 deletions
+36
View File
@@ -0,0 +1,36 @@
# -*- 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_CppunitTest_CppunitTest,singletons))
$(eval $(call gb_CppunitTest_add_exception_objects,singletons, \
postprocess/qa/singletons \
))
$(eval $(call gb_CppunitTest_use_libraries,singletons, \
comphelper \
cppu \
cppuhelper \
sal \
test \
unotest \
vcl \
))
$(eval $(call gb_CppunitTest_use_sdk_api,singletons))
$(eval $(call gb_CppunitTest_use_api,singletons,oovbaapi))
$(eval $(call gb_CppunitTest_use_ure,singletons))
$(eval $(call gb_CppunitTest_use_vcl,singletons))
$(eval $(call gb_CppunitTest_use_rdb,singletons,services))
$(eval $(call gb_CppunitTest_use_configuration,singletons))
# vim: set noet sw=4 ts=4:
+4
View File
@@ -63,4 +63,8 @@ $(eval $(call gb_Module_add_check_targets,postprocess,\
))
endif
$(eval $(call gb_Module_add_check_targets,postprocess,\
CppunitTest_singletons \
))
# vim: set noet sw=4 ts=4:
+98
View File
@@ -0,0 +1,98 @@
/* -*- 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/.
*/
// Tries to get every interface-based singleton registered in the type description manager using its
// type name. See tdf#170930 for an example of a mistake that can make this fail.
#include <sal/config.h>
#include <com/sun/star/reflection/XTypeDescriptionEnumerationAccess.hpp>
#include <com/sun/star/reflection/XSingletonTypeDescription2.hpp>
#include <test/bootstrapfixture.hxx>
namespace
{
constexpr OUString TYPE_DESCRIPTION_MANAGER
= u"/singletons/com.sun.star.reflection.theTypeDescriptionManager"_ustr;
class Test : public test::BootstrapFixture
{
public:
void test();
CPPUNIT_TEST_SUITE(Test);
CPPUNIT_TEST(test);
CPPUNIT_TEST_SUITE_END();
};
void Test::test()
{
css::uno::Reference<css::reflection::XTypeDescriptionEnumerationAccess> xTDMgr;
m_xContext->getValueByName(TYPE_DESCRIPTION_MANAGER) >>= xTDMgr;
if (!xTDMgr.is())
throw css::uno::RuntimeException("cannot get singleton " + TYPE_DESCRIPTION_MANAGER);
css::uno::Sequence<css::uno::TypeClass> aTypes = { css::uno::TypeClass_SINGLETON };
css::uno::Reference<css::reflection::XTypeDescriptionEnumeration> xTypeEnum
= xTDMgr->createTypeDescriptionEnumeration(
"", aTypes, css::reflection::TypeDescriptionSearchDepth_INFINITE);
while (true)
{
css::uno::Reference<css::reflection::XTypeDescription> xType;
try
{
xType = xTypeEnum->nextTypeDescription();
}
catch (css::container::NoSuchElementException&)
{
break;
}
css::uno::Reference<css::reflection::XSingletonTypeDescription2> xSingleton(
xType, css::uno::UNO_QUERY);
// Skip singletons that are not interface-based
if (!xSingleton.is() || !xSingleton->isInterfaceBased())
continue;
OUString sName = "/singletons/" + xSingleton->getName();
css::uno::Reference<css::uno::XInterface> xImpl;
m_xContext->getValueByName(sName) >>= xImpl;
if (!xImpl.is())
throw css::uno::RuntimeException("cannot get singleton " + sName);
css::uno::Reference<css::reflection::XTypeDescription> xInterface
= xSingleton->getInterface();
css::uno::Type interfaceType(xInterface->getTypeClass(), xInterface->getName());
// Make sure that the returned object supports the interface of the singleton
if (!xImpl->queryInterface(interfaceType).hasValue())
{
throw css::uno::RuntimeException("Singleton " + xSingleton->getName()
+ " doesn’t support the " + xInterface->getName()
+ " interface");
}
}
}
CPPUNIT_TEST_SUITE_REGISTRATION(Test);
}
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */