LCOV - code coverage report
Current view: top level - postprocess/qa - services.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 149 163 91.4 %
Date: 2015-06-13 12:38:46 Functions: 26 27 96.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       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/.
       8             :  */
       9             : 
      10             : // Try to instantiate as many implementations as possible.  Finds all
      11             : // implementations reachable via the service manager.  If a given implementation
      12             : // is the only implementor of some service that has a zero-parameter
      13             : // constructor, instantiate the implementation through that service name.  If a
      14             : // given implementation does not offer any such contructors (because it does not
      15             : // support any single-interface--based service, or because for each relevant
      16             : // service there are multiple implementations or it does not have an appropriate
      17             : // constructor) but does support at least one accumulation-based service, then
      18             : // instantiate it through its implementation name (a heuristic to identify
      19             : // instantiatable implementations that appears to work well).
      20             : 
      21             : #include <sal/config.h>
      22             : 
      23             : #include <algorithm>
      24             : #include <cassert>
      25             : #include <iostream>
      26             : #include <map>
      27             : #include <utility>
      28             : #include <vector>
      29             : 
      30             : #include <com/sun/star/container/XContentEnumerationAccess.hpp>
      31             : #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
      32             : #include <com/sun/star/lang/XComponent.hpp>
      33             : #include <com/sun/star/lang/XServiceInfo.hpp>
      34             : #include <com/sun/star/reflection/XServiceConstructorDescription.hpp>
      35             : #include <com/sun/star/reflection/XServiceTypeDescription2.hpp>
      36             : #include <cppuhelper/exc_hlp.hxx>
      37             : #include <rtl/strbuf.hxx>
      38             : #include <test/bootstrapfixture.hxx>
      39             : #include <vcl/svapp.hxx>
      40             : 
      41             : namespace {
      42             : 
      43       16803 : OString msg(OUString const & string) {
      44       16803 :     return OUStringToOString(string, osl_getThreadTextEncoding());
      45             : }
      46             : 
      47        4168 : OString msg(css::uno::Sequence<OUString> const & strings) {
      48        4168 :     OStringBuffer buf("{");
      49       11020 :     for (sal_Int32 i = 0; i != strings.getLength(); ++i) {
      50        6852 :         if (i != 0) {
      51        2684 :             buf.append(", ");
      52             :         }
      53        6852 :         buf.append('"');
      54        6852 :         buf.append(msg(strings[i]));
      55        6852 :         buf.append('"');
      56             :     }
      57        4168 :     buf.append('}');
      58        4168 :     return buf.makeStringAndClear();
      59             : }
      60             : 
      61        1643 : bool unique(css::uno::Sequence<OUString> const & strings) {
      62             :     // Assumes small sequences for which quadratic algorithm is acceptable:
      63        2572 :     for (sal_Int32 i = 0; i < strings.getLength() - 1; ++i) {
      64        3597 :         for (sal_Int32 j = i + 1; j != strings.getLength(); ++j) {
      65        2668 :             if (strings[j] == strings[i]) {
      66           0 :                 return false;
      67             :             }
      68             :         }
      69             :     }
      70        1643 :     return true;
      71             : }
      72             : 
      73        2207 : bool contains(
      74             :     css::uno::Sequence<OUString> const & strings, OUString const & string)
      75             : {
      76        3887 :     for (sal_Int32 i = 0; i != strings.getLength(); ++i) {
      77        3887 :         if (string == strings[i]) {
      78        2207 :             return true;
      79             :         }
      80             :     }
      81           0 :     return false;
      82             : }
      83             : 
      84         594 : bool contains(
      85             :     css::uno::Sequence<OUString> const & strings1,
      86             :     css::uno::Sequence<OUString> const & strings2)
      87             : {
      88             :     // Assumes small sequences for which quadratic algorithm is acceptable:
      89        1464 :     for (sal_Int32 i = 0; i != strings2.getLength(); ++i) {
      90         870 :         if (!contains(strings1, strings2[i])) {
      91           0 :             return false;
      92             :         }
      93             :     }
      94         594 :     return true;
      95             : }
      96             : 
      97           3 : class Test: public test::BootstrapFixture {
      98             : public:
      99             :     void test();
     100             : 
     101           2 :     CPPUNIT_TEST_SUITE(Test);
     102           1 :     CPPUNIT_TEST(test);
     103           5 :     CPPUNIT_TEST_SUITE_END();
     104             : 
     105             : private:
     106             :     void createInstance(
     107             :         OUString const & name, bool withArguments,
     108             :         OUString const & implementationName,
     109             :         css::uno::Sequence<OUString> const & serviceNames,
     110             :         std::vector<css::uno::Reference<css::lang::XComponent>> * components);
     111             : };
     112             : 
     113           1 : void Test::test() {
     114             :     // On Windows, blacklist the com.sun.star.comp.report.OReportDefinition
     115             :     // implementation (reportdesign::OReportDefinition in
     116             :     // reportdesign/source/core/api/ReportDefinition.cxx), as it spawns a thread
     117             :     // that forever blocks in SendMessageW when no VCL event loop is running
     118             :     // (reportdesign::<anon>::FactoryLoader::execute ->
     119             :     // framework::Desktop::findFrame -> framework::TaskCreator::createTask ->
     120             :     // <anon>::TaskCreatorService::createInstanceWithArguments ->
     121             :     // <anon>::TaskCreatorService::impls_createContainerWindow ->
     122             :     // <anon>::VCLXToolkit::createWindow ->
     123             :     // <anon>::VCLXToolkit::ImplCreateWindow ->
     124             :     // <anon>::VCLXToolkit::ImplCreateWindow -> WorkWindow::WorkWindow ->
     125             :     // WorkWindow::ImplInit -> ImplBorderWindow::ImplBorderWindow ->
     126             :     // ImplBorderWindow::ImplInit -> Window::ImplInit ->
     127             :     // WinSalInstance::CreateFrame -> ImplSendMessage -> SendMessageW):
     128           1 :     std::vector<OUString> blacklist;
     129           1 :     blacklist.push_back("com.sun.star.comp.report.OReportDefinition");
     130             : 
     131             :     // <https://bugs.documentfoundation.org/show_bug.cgi?id=89343>
     132             :     // "~SwXMailMerge() goes into endless SwCache::Check()":
     133           1 :     blacklist.push_back("SwXMailMerge");
     134             : 
     135             :     css::uno::Reference<css::container::XContentEnumerationAccess> enumAcc(
     136           2 :         m_xContext->getServiceManager(), css::uno::UNO_QUERY_THROW);
     137             :     css::uno::Reference<css::container::XHierarchicalNameAccess> typeMgr(
     138           1 :         m_xContext->getValueByName(
     139           1 :             "/singletons/com.sun.star.reflection.theTypeDescriptionManager"),
     140           2 :         css::uno::UNO_QUERY_THROW);
     141             :     css::uno::Sequence<OUString> serviceNames(
     142           2 :         m_xContext->getServiceManager()->getAvailableServiceNames());
     143         725 :     struct Constructor {
     144         239 :         Constructor(
     145             :             OUString const & theServiceName, bool theDefaultConstructor):
     146             :             serviceName(theServiceName),
     147         239 :             defaultConstructor(theDefaultConstructor)
     148         239 :         {}
     149             :         OUString serviceName;
     150             :         bool defaultConstructor;
     151             :     };
     152        5245 :     struct Implementation {
     153        1049 :         Implementation(
     154             :             css::uno::Reference<css::lang::XServiceInfo> const & theFactory,
     155             :             css::uno::Sequence<OUString> const & theServiceNames):
     156             :             factory(theFactory), serviceNames(theServiceNames),
     157        1049 :             accumulationBased(false)
     158        1049 :         {}
     159             :         css::uno::Reference<css::lang::XServiceInfo> const factory;
     160             :         css::uno::Sequence<OUString> const serviceNames;
     161             :         std::vector<Constructor> constructors;
     162             :         bool accumulationBased;
     163             :     };
     164           2 :     std::map<OUString, Implementation> impls;
     165         989 :     for (sal_Int32 i = 0; i != serviceNames.getLength(); ++i) {
     166             :         css::uno::Reference<css::container::XEnumeration> serviceImpls1(
     167         988 :             enumAcc->createContentEnumeration(serviceNames[i]),
     168         988 :             css::uno::UNO_SET_THROW);
     169        1976 :         std::vector<css::uno::Reference<css::lang::XServiceInfo>> serviceImpls2;
     170        3313 :         while (serviceImpls1->hasMoreElements()) {
     171             :             serviceImpls2.push_back(
     172             :                 css::uno::Reference<css::lang::XServiceInfo>(
     173        1337 :                     serviceImpls1->nextElement(), css::uno::UNO_QUERY_THROW));
     174             :         }
     175        1976 :         css::uno::Reference<css::reflection::XServiceTypeDescription2> desc;
     176         988 :         if (typeMgr->hasByHierarchicalName(serviceNames[i])) {
     177             :             desc.set(
     178         590 :                 typeMgr->getByHierarchicalName(serviceNames[i]),
     179         590 :                 css::uno::UNO_QUERY_THROW);
     180             :         }
     181         988 :         if (serviceImpls2.empty()) {
     182           0 :             if (desc.is()) {
     183           0 :                 CPPUNIT_ASSERT_MESSAGE(
     184             :                     (OString(
     185             :                         "no implementations of single-interface--based \""
     186             :                         + msg(serviceNames[i]) + "\"")
     187             :                      .getStr()),
     188           0 :                     !desc->isSingleInterfaceBased());
     189             :                 std::cout
     190           0 :                     << "accumulation-based service \"" << serviceNames[i]
     191           0 :                     << "\" without implementations\n";
     192             :             } else {
     193             :                 std::cout
     194           0 :                     << "fantasy service name \"" << serviceNames[i]
     195           0 :                     << "\" without implementations\n";
     196             :             }
     197             :         } else {
     198        2325 :             for (auto const & j: serviceImpls2) {
     199        1337 :                 OUString name(j->getImplementationName());
     200        1337 :                 auto k = impls.find(name);
     201        1337 :                 if (k == impls.end()) {
     202             :                     css::uno::Sequence<OUString> servs(
     203        1049 :                         j->getSupportedServiceNames());
     204        2098 :                     CPPUNIT_ASSERT_MESSAGE(
     205             :                         (OString(
     206             :                             "implementation \"" + msg(name)
     207             :                             + "\" supports non-unique " + msg(servs))
     208             :                          .getStr()),
     209        1049 :                         unique(servs));
     210             :                     k = impls.insert(
     211        2098 :                             std::make_pair(name, Implementation(j, servs)))
     212        2098 :                         .first;
     213             :                 } else {
     214         576 :                     CPPUNIT_ASSERT_MESSAGE(
     215             :                         (OString(
     216             :                             "multiple implementations named \"" + msg(name)
     217             :                             + "\"")
     218             :                          .getStr()),
     219         288 :                         j == k->second.factory);
     220             :                 }
     221        2674 :                 CPPUNIT_ASSERT_MESSAGE(
     222             :                     (OString(
     223             :                         "implementation \"" + msg(name) + "\" supports "
     224             :                         + msg(k->second.serviceNames) + " but not \""
     225             :                         + msg(serviceNames[i]) + "\"")
     226             :                      .getStr()),
     227        1337 :                     contains(k->second.serviceNames, serviceNames[i]));
     228        1337 :                 if (desc.is()) {
     229         813 :                     if (desc->isSingleInterfaceBased()) {
     230         322 :                         if (serviceImpls2.size() == 1) {
     231             :                             css::uno::Sequence<
     232             :                                 css::uno::Reference<
     233             :                                     css::reflection::XServiceConstructorDescription>>
     234         310 :                                         ctors(desc->getConstructors());
     235         392 :                             for (sal_Int32 l = 0; l != ctors.getLength(); ++l) {
     236         321 :                                 if (!ctors[l]->getParameters().hasElements()) {
     237         239 :                                     k->second.constructors.push_back(
     238             :                                         Constructor(
     239         239 :                                             serviceNames[i],
     240         717 :                                             ctors[l]->isDefaultConstructor()));
     241         239 :                                     break;
     242             :                                 }
     243         310 :                             }
     244             :                         }
     245             :                     } else {
     246         491 :                         k->second.accumulationBased = true;
     247             :                     }
     248             :                 } else {
     249             :                     std::cout
     250         524 :                         << "implementation \"" << name
     251         524 :                         << "\" supports fantasy service name \""
     252        1048 :                         << serviceNames[i] << "\"\n";
     253             :                 }
     254        1337 :             }
     255             :         }
     256         988 :     }
     257           2 :     std::vector<css::uno::Reference<css::lang::XComponent>> comps;
     258        1050 :     for (auto const & i: impls) {
     259        3147 :         if (std::find(blacklist.begin(), blacklist.end(), i.first)
     260        3147 :             == blacklist.end())
     261             :         {
     262        1047 :             if (i.second.constructors.empty()) {
     263         813 :                 if (i.second.accumulationBased) {
     264             :                     createInstance(
     265         356 :                         i.first, false, i.first, i.second.serviceNames, &comps);
     266             :                 } else {
     267             :                     std::cout
     268         457 :                         << "no obvious way to instantiate implementation \""
     269         914 :                         << i.first << "\"\n";
     270             :                 }
     271             :             } else {
     272         472 :                 for (auto const & j: i.second.constructors) {
     273             :                     createInstance(
     274         238 :                         j.serviceName, !j.defaultConstructor, i.first,
     275         476 :                         i.second.serviceNames, &comps);
     276             :                 }
     277             :             }
     278             :         }
     279             :     }
     280           2 :     SolarMutexReleaser rel;
     281         260 :     for (auto const & i: comps) {
     282         259 :         i->dispose();
     283           1 :     }
     284           1 : }
     285             : 
     286         594 : void Test::createInstance(
     287             :     OUString const & name, bool withArguments,
     288             :     OUString const & implementationName,
     289             :     css::uno::Sequence<OUString> const & serviceNames,
     290             :     std::vector<css::uno::Reference<css::lang::XComponent>> * components)
     291             : {
     292             :     assert(components != nullptr);
     293         594 :     css::uno::Reference<css::uno::XInterface> inst;
     294             :     try {
     295         594 :         if (withArguments) {
     296          75 :             inst = m_xContext->getServiceManager()
     297          50 :                 ->createInstanceWithArgumentsAndContext(
     298          50 :                     name, css::uno::Sequence<css::uno::Any>(), m_xContext);
     299             :         } else {
     300        1707 :             inst = m_xContext->getServiceManager()->createInstanceWithContext(
     301        1138 :                 name, m_xContext);
     302             :         }
     303           0 :     } catch (css::uno::Exception & e) {
     304           0 :         css::uno::Any a(cppu::getCaughtException());
     305           0 :         CPPUNIT_FAIL(
     306             :             OString(
     307             :                 "instantiating \"" + msg(implementationName) + "\" via \""
     308             :                 + msg(name) + "\"  caused " + msg(a.getValueTypeName()) + " \""
     309             :                 + msg(e.Message) + "\"")
     310           0 :             .getStr());
     311             :     }
     312        1188 :     CPPUNIT_ASSERT_MESSAGE(
     313             :         (OString(
     314             :             "instantiating \"" + msg(implementationName) + "\" via \""
     315             :             + msg(name) + "\" returned null reference")
     316             :          .getStr()),
     317         594 :         inst.is());
     318        1188 :     css::uno::Reference<css::lang::XComponent> comp(inst, css::uno::UNO_QUERY);
     319         594 :     if (comp.is()) {
     320         259 :         components->push_back(comp);
     321             :     }
     322             :     css::uno::Reference<css::lang::XServiceInfo> info(
     323        1188 :         inst, css::uno::UNO_QUERY);
     324        1188 :     CPPUNIT_ASSERT_MESSAGE(
     325             :         (OString(
     326             :             "instantiating \"" + msg(implementationName) + "\" via \""
     327             :             + msg(name) + "\" does not provide XServiceInfo")
     328             :          .getStr()),
     329         594 :         info.is());
     330        1188 :     OUString expImpl(implementationName);
     331        1188 :     css::uno::Sequence<OUString> expServs(serviceNames);
     332             :     // Special cases:
     333         594 :     if (name == "com.sun.star.comp.configuration.ConfigurationProvider") {
     334             :         // Instantiating a ConfigurationProvider with no or empty args must
     335             :         // return theDefaultProvider:
     336           1 :         expImpl = "com.sun.star.comp.configuration.DefaultProvider";
     337           1 :         expServs = {"com.sun.star.configuration.DefaultProvider"};
     338         593 :     } else if (name == "com.sun.star.datatransfer.clipboard.SystemClipboard") {
     339             :         // SystemClipboard is a wrapper returning either a platform-specific or
     340             :         // the generic VCLGenericClipboard:
     341             : #if defined WNT
     342             :         expImpl = "com.sun.star.datatransfer.clipboard.ClipboardW32";
     343             : #else
     344           1 :         expImpl = "com.sun.star.datatransfer.VCLGenericClipboard";
     345             : #endif
     346             : #if !defined WNT
     347        1184 :     } else if (name == "com.sun.star.comp.datatransfer.dnd.OleDragSource_V1"
     348         592 :                || name == "com.sun.star.datatransfer.dnd.XdndSupport")
     349             :     {
     350           1 :         expImpl = "com.sun.star.datatransfer.dnd.VclGenericDragSource";
     351           1 :         expServs = {"com.sun.star.datatransfer.dnd.GenericDragSource"};
     352        1182 :     } else if (name == "com.sun.star.comp.datatransfer.dnd.OleDropTarget_V1"
     353         591 :                || name == "com.sun.star.datatransfer.dnd.XdndDropTarget")
     354             :     {
     355           1 :         expImpl = "com.sun.star.datatransfer.dnd.VclGenericDropTarget";
     356           1 :         expServs = {"com.sun.star.datatransfer.dnd.GenericDropTarget"};
     357             : #endif
     358         590 :     } else if (name == "com.sun.star.ui.dialogs.FolderPicker") {
     359             :         // FolderPicker is a wrapper returning either a platform-specific or the
     360             :         // generic OfficeFolderPicker:
     361             : #if defined WNT
     362             :         expImpl = "com.sun.star.ui.dialogs.Win32FolderPicker";
     363             :         expServs = {"com.sun.star.ui.dialogs.SystemFolderPicker"};
     364             : #else
     365           1 :         expImpl = "com.sun.star.svtools.OfficeFolderPicker";
     366           1 :         expServs = {"com.sun.star.ui.dialogs.OfficeFolderPicker"};
     367             : #endif
     368             :     }
     369        1188 :     CPPUNIT_ASSERT_EQUAL_MESSAGE(
     370             :         (OString(
     371             :             "instantiating \"" + msg(implementationName) + "\" via \""
     372             :             + msg(name) + "\" reports wrong implementation name")
     373             :          .getStr()),
     374         594 :         expImpl, info->getImplementationName());
     375        1188 :     css::uno::Sequence<OUString> servs(info->getSupportedServiceNames());
     376        1188 :     CPPUNIT_ASSERT_MESSAGE(
     377             :         (OString(
     378             :             "instantiating \"" + msg(implementationName) + "\" via \""
     379             :             + msg(name) + "\" reports non-unique " + msg(servs))
     380             :          .getStr()),
     381         594 :         unique(servs));
     382             :     // Some implementations like "com.sun.star.comp.Calc.SpreadsheetDocument"
     383             :     // report sub-services like
     384             :     // "com.sun.star.sheet.SpreadsheetDocumentSettings", and
     385             :     // "com.sun.star.document.OfficeDocument" that are not listed in the
     386             :     // .component file, so check for containment instead of equality:
     387        1188 :     CPPUNIT_ASSERT_MESSAGE(
     388             :         (OString(
     389             :             "instantiating \"" + msg(implementationName) + "\" via \""
     390             :             + msg(name) + "\" reports " + msg(servs) + " different from "
     391             :             + msg(expServs))
     392             :          .getStr()),
     393        1188 :         contains(servs, expServs));
     394         594 : }
     395             : 
     396           1 : CPPUNIT_TEST_SUITE_REGISTRATION(Test);
     397             : 
     398             : }
     399             : 
     400           4 : CPPUNIT_PLUGIN_IMPLEMENT();
     401             : 
     402             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11