Make CppunitTest_services instantiate even more services

Change-Id: Id9bfb3886e4a9cbc15a7bf7ef3aefa73bd160e3b
This commit is contained in:
Stephan Bergmann 2015-02-12 16:00:17 +01:00
parent 5d8dc045f1
commit f7cd7b2ce4
3 changed files with 193 additions and 75 deletions

View File

@ -494,7 +494,6 @@ certain functionality.
@li @c jvmaccess @li @c jvmaccess
@li @c linguistic @li @c linguistic
@li @c mysqlc @li @c mysqlc
@li @c postprocess.cppunit
@li @c registry @li @c registry
@li @c reportdesign @li @c reportdesign
@li @c rsc @li @c rsc

View File

@ -19,6 +19,7 @@ $(eval $(call gb_CppunitTest_use_externals,services, \
$(eval $(call gb_CppunitTest_use_libraries,services, \ $(eval $(call gb_CppunitTest_use_libraries,services, \
cppu \ cppu \
cppuhelper \
sal \ sal \
test \ test \
vcl \ vcl \
@ -26,6 +27,7 @@ $(eval $(call gb_CppunitTest_use_libraries,services, \
)) ))
$(eval $(call gb_CppunitTest_use_sdk_api,services)) $(eval $(call gb_CppunitTest_use_sdk_api,services))
$(eval $(call gb_CppunitTest_use_api,services,oovbaapi))
$(eval $(call gb_CppunitTest_use_ure,services)) $(eval $(call gb_CppunitTest_use_ure,services))
$(eval $(call gb_CppunitTest_use_vcl,services)) $(eval $(call gb_CppunitTest_use_vcl,services))

View File

@ -7,42 +7,61 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
// Try to instantiate as many implementations as possible. Finds all
// implementations reachable via the service manager. If a given implementation
// is the only implementor of some service that has a zero-parameter
// constructor, instantiate the implementation through that service name. If a
// given implementation does not offer any such contructors (because it does not
// support any single-interface--based service, or because for each relevant
// service there are multiple implementations or it does not have an appropriate
// constructor) but does support at least one accumulation-based service, then
// instantiate it through its implementation name (a heuristic to identify
// instantiatable implementations that appears to work well).
#include <sal/config.h> #include <sal/config.h>
#include <algorithm> #include <algorithm>
#include <cassert>
#include <iostream>
#include <map>
#include <utility>
#include <vector> #include <vector>
#include <com/sun/star/container/XContentEnumerationAccess.hpp>
#include <com/sun/star/container/XHierarchicalNameAccess.hpp> #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
#include <com/sun/star/lang/XComponent.hpp> #include <com/sun/star/lang/XComponent.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/reflection/XServiceConstructorDescription.hpp> #include <com/sun/star/reflection/XServiceConstructorDescription.hpp>
#include <com/sun/star/reflection/XServiceTypeDescription2.hpp> #include <com/sun/star/reflection/XServiceTypeDescription2.hpp>
#include <cppuhelper/exc_hlp.hxx>
#include <test/bootstrapfixture.hxx> #include <test/bootstrapfixture.hxx>
#include <vcl/svapp.hxx> #include <vcl/svapp.hxx>
using namespace css::container;
using namespace css::reflection;
using namespace css::uno;
namespace { namespace {
class ServicesTest: public test::BootstrapFixture OString msg(OUString const & string) {
{ return OUStringToOString(string, osl_getThreadTextEncoding());
}
class Test: public test::BootstrapFixture {
public: public:
void test(); void test();
CPPUNIT_TEST_SUITE(ServicesTest); CPPUNIT_TEST_SUITE(Test);
CPPUNIT_TEST(test); CPPUNIT_TEST(test);
CPPUNIT_TEST_SUITE_END(); CPPUNIT_TEST_SUITE_END();
private:
void createInstance(
OUString const & name, bool withArguments,
std::vector<css::uno::Reference<css::lang::XComponent>> * components);
}; };
void ServicesTest::test() void Test::test() {
{ // On Windows, blacklist the com.sun.star.comp.report.OReportDefinition
std::vector<OUString> blacklist; // implementation (reportdesign::OReportDefinition in
// reportdesign/source/core/api/ReportDefinition.cxx), as it spawns a thread
// On Windows, blacklist the com.sun.star.report.ReportDefinition service, // that forever blocks in SendMessageW when no VCL event loop is running
// as its reportdesign::OReportDefinition implementation (in
// reportdesign/source/core/api/ReportDefinition.cxx) spawns a thread that
// forever blocks in SendMessageW when no VCL event loop is running
// (reportdesign::<anon>::FactoryLoader::execute -> // (reportdesign::<anon>::FactoryLoader::execute ->
// framework::Desktop::findFrame -> framework::TaskCreator::createTask -> // framework::Desktop::findFrame -> framework::TaskCreator::createTask ->
// <anon>::TaskCreatorService::createInstanceWithArguments -> // <anon>::TaskCreatorService::createInstanceWithArguments ->
@ -53,76 +72,174 @@ void ServicesTest::test()
// WorkWindow::ImplInit -> ImplBorderWindow::ImplBorderWindow -> // WorkWindow::ImplInit -> ImplBorderWindow::ImplBorderWindow ->
// ImplBorderWindow::ImplInit -> Window::ImplInit -> // ImplBorderWindow::ImplInit -> Window::ImplInit ->
// WinSalInstance::CreateFrame -> ImplSendMessage -> SendMessageW): // WinSalInstance::CreateFrame -> ImplSendMessage -> SendMessageW):
blacklist.push_back("com.sun.star.report.ReportDefinition"); std::vector<OUString> blacklist;
blacklist.push_back("com.sun.star.comp.report.OReportDefinition");
Reference< XHierarchicalNameAccess > xTypeManager( //TODO: bug ID
m_xContext->getValueByName( blacklist.push_back("SwXMailMerge");
"/singletons/com.sun.star.reflection.theTypeDescriptionManager"),
UNO_QUERY_THROW ); css::uno::Reference<css::container::XContentEnumerationAccess> enumAcc(
Sequence<OUString> s = m_xContext->getServiceManager()->getAvailableServiceNames(); m_xContext->getServiceManager(), css::uno::UNO_QUERY_THROW);
std::vector< css::uno::Reference<css::lang::XComponent> > comps; css::uno::Reference<css::container::XHierarchicalNameAccess> typeMgr(
for (sal_Int32 i = 0; i < s.getLength(); i++) m_xContext->getValueByName(
{ "/singletons/com.sun.star.reflection.theTypeDescriptionManager"),
if (std::find(blacklist.begin(), blacklist.end(), s[i]) css::uno::UNO_QUERY_THROW);
!= blacklist.end()) css::uno::Sequence<OUString> serviceNames(
{ m_xContext->getServiceManager()->getAvailableServiceNames());
continue; struct Constructor {
Constructor(
OUString const & theServiceName, bool theDefaultConstructor):
serviceName(theServiceName),
defaultConstructor(theDefaultConstructor)
{}
OUString serviceName;
bool defaultConstructor;
};
struct Implementation {
Implementation(css::uno::Reference<css::lang::XServiceInfo> theFactory):
factory(theFactory), accumulationBased(false) {}
css::uno::Reference<css::lang::XServiceInfo> factory;
std::vector<Constructor> constructors;
bool accumulationBased;
};
std::map<OUString, Implementation> impls;
for (sal_Int32 i = 0; i != serviceNames.getLength(); ++i) {
css::uno::Reference<css::container::XEnumeration> serviceImpls1(
enumAcc->createContentEnumeration(serviceNames[i]),
css::uno::UNO_SET_THROW);
std::vector<css::uno::Reference<css::lang::XServiceInfo>> serviceImpls2;
while (serviceImpls1->hasMoreElements()) {
serviceImpls2.push_back(
css::uno::Reference<css::lang::XServiceInfo>(
serviceImpls1->nextElement(), css::uno::UNO_QUERY_THROW));
} }
if (!xTypeManager->hasByHierarchicalName(s[i])) css::uno::Reference<css::reflection::XServiceTypeDescription2> desc;
{ if (typeMgr->hasByHierarchicalName(serviceNames[i])) {
SAL_WARN( desc.set(
"postprocess.cppunit", typeMgr->getByHierarchicalName(serviceNames[i]),
"fantasy service name \"" << s[i] << "\""); css::uno::UNO_QUERY_THROW);
continue;
} }
SAL_WARN( if (serviceImpls2.empty()) {
"postprocess.cppunit", if (desc.is()) {
"trying (index: " << i << ") \"" << s[i] << "\""); CPPUNIT_ASSERT_MESSAGE(
Reference< XServiceTypeDescription2 > xDesc( (OString(
xTypeManager->getByHierarchicalName(s[i]), UNO_QUERY_THROW); "no implementations of singlie-interface--based \""
Sequence< Reference< XServiceConstructorDescription > > xseq = xDesc->getConstructors(); + msg(serviceNames[i]) + "\"")
SAL_WARN_IF(xseq.getLength() == 0, "postprocess.cppunit", "not tested because there is no constructor"); .getStr()),
for (sal_Int32 c = 0; c < xseq.getLength(); c++) !desc->isSingleInterfaceBased());
if (!xseq[c]->getParameters().hasElements()) std::cout
{ << "accumulation-based service \"" << serviceNames[i]
Reference< XInterface > instance; << "\" without implementations\n";
try } else {
{ std::cout
OString message = OUStringToOString(s[i], RTL_TEXTENCODING_UTF8); << "fantasy service name \"" << serviceNames[i]
bool bDefConstructor = xseq[c]->isDefaultConstructor(); << "\" without implementations\n";
Reference< css::lang::XMultiComponentFactory > serviceManager = m_xContext->getServiceManager(); }
} else {
if( bDefConstructor ) for (auto const & j: serviceImpls2) {
instance = serviceManager->createInstanceWithContext(s[i], m_xContext); OUString name(j->getImplementationName());
else auto k = impls.find(name);
instance = serviceManager->createInstanceWithArgumentsAndContext( if (k == impls.end()) {
s[i], css::uno::Sequence<css::uno::Any>(), m_xContext); k = impls.insert(std::make_pair(name, Implementation(j)))
.first;
CPPUNIT_ASSERT_MESSAGE( message.getStr(), instance.is() ); } else {
CPPUNIT_ASSERT_MESSAGE(
(OString(
"multiple implementations named \"" + msg(name)
+ "\"")
.getStr()),
j == k->second.factory);
} }
catch(const Exception & e) if (desc.is()) {
{ if (desc->isSingleInterfaceBased()) {
OString exc = "Exception thrown while creating " + if (serviceImpls2.size() == 1) {
OUStringToOString(s[i] + ": " + e.Message, RTL_TEXTENCODING_UTF8); css::uno::Sequence<
CPPUNIT_FAIL(exc.getStr()); css::uno::Reference<
} css::reflection::XServiceConstructorDescription>>
css::uno::Reference<css::lang::XComponent> comp( ctors(desc->getConstructors());
instance, css::uno::UNO_QUERY); for (sal_Int32 l = 0; l != ctors.getLength(); ++l) {
if (comp.is()) { if (!ctors[l]->getParameters().hasElements()) {
comps.push_back(comp); k->second.constructors.push_back(
Constructor(
serviceNames[i],
ctors[l]->isDefaultConstructor()));
break;
}
}
}
} else {
k->second.accumulationBased = true;
}
} else {
std::cout
<< "implementation \"" << name
<< "\" supports fantasy service name \""
<< serviceNames[i] << "\"\n";
} }
} }
}
}
std::vector<css::uno::Reference<css::lang::XComponent>> comps;
for (auto const & i: impls) {
if (std::find(blacklist.begin(), blacklist.end(), i.first)
== blacklist.end())
{
if (i.second.constructors.empty()) {
if (i.second.accumulationBased) {
createInstance(i.first, false, &comps);
} else {
std::cout
<< "no obvious way to instantiate implementation \""
<< i.first << "\"\n";
}
} else {
for (auto const & j: i.second.constructors) {
createInstance(
j.serviceName, !j.defaultConstructor, &comps);
}
}
}
} }
SolarMutexReleaser rel; SolarMutexReleaser rel;
for (std::vector< css::uno::Reference<css::lang::XComponent> >::iterator i( for (auto const & i: comps) {
comps.begin()); i->dispose();
i != comps.end(); ++i)
{
(*i)->dispose();
} }
} }
CPPUNIT_TEST_SUITE_REGISTRATION(ServicesTest); void Test::createInstance(
OUString const & name, bool withArguments,
std::vector<css::uno::Reference<css::lang::XComponent>> * components)
{
assert(components != nullptr);
css::uno::Reference<css::uno::XInterface> inst;
try {
if (withArguments) {
inst = m_xContext->getServiceManager()
->createInstanceWithArgumentsAndContext(
name, css::uno::Sequence<css::uno::Any>(), m_xContext);
} else {
inst = m_xContext->getServiceManager()->createInstanceWithContext(
name, m_xContext);
}
} catch (css::uno::Exception & e) {
css::uno::Any a(cppu::getCaughtException());
CPPUNIT_FAIL(
OString(
"creating \"" + msg(name) + "\" caused "
+ msg(a.getValueTypeName()) + " \"" + msg(e.Message) + "\"")
.getStr());
}
CPPUNIT_ASSERT_MESSAGE(
(OString("creating \"" + msg(name) + "\" returned null reference")
.getStr()),
inst.is());
css::uno::Reference<css::lang::XComponent> comp(inst, css::uno::UNO_QUERY);
if (comp.is()) {
components->push_back(comp);
}
}
CPPUNIT_TEST_SUITE_REGISTRATION(Test);
} }