--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/auto/qservicemanager/tst_qservicemanager.cpp Wed Aug 25 15:49:42 2010 +0300
@@ -0,0 +1,1495 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <qservicemanager.h>
+#include <qservicecontext.h>
+#include <qabstractsecuritysession.h>
+#include <qserviceinterfacedescriptor_p.h>
+#include "../../sampleserviceplugin/sampleserviceplugin.h"
+#include "../qsfwtestutil.h"
+
+#include <QtTest/QtTest>
+#include <QtCore>
+#include <QSettings>
+#include <QFileInfo>
+#include <QDir>
+#include <QPair>
+
+#define QTRY_COMPARE(a,e) \
+ for (int _i = 0; _i < 5000; _i += 100) { \
+ if ((a) == (e)) break; \
+ QTest::qWait(100); \
+ } \
+ QCOMPARE(a, e)
+
+#define QTRY_VERIFY(a) \
+ for (int _i = 0; _i < 5000; _i += 100) { \
+ if (a) break; \
+ QTest::qWait(100); \
+ } \
+ QVERIFY(a)
+
+#define PRINT_ERR(a) qPrintable(QString("error = %1").arg(a.error()))
+
+typedef QList<QtMobility::QServiceInterfaceDescriptor> ServiceInterfaceDescriptorList;
+Q_DECLARE_METATYPE(QtMobility::QServiceFilter)
+Q_DECLARE_METATYPE(QtMobility::QServiceInterfaceDescriptor)
+Q_DECLARE_METATYPE(ServiceInterfaceDescriptorList)
+
+Q_DECLARE_METATYPE(QSet<QString>)
+Q_DECLARE_METATYPE(QList<QByteArray>)
+Q_DECLARE_METATYPE(QtMobility::QService::Scope)
+
+QTM_BEGIN_NAMESPACE
+typedef QHash<QtMobility::QServiceInterfaceDescriptor::Attribute, QVariant> DescriptorAttributes;
+
+inline uint qHash(const QtMobility::QServiceInterfaceDescriptor &desc)
+{
+ return qHash(desc.serviceName()) + qHash(desc.interfaceName()) + desc.majorVersion() * 7 + desc.minorVersion() * 7;
+}
+QTM_END_NAMESPACE
+
+QTM_USE_NAMESPACE
+static DescriptorAttributes defaultDescriptorAttributes()
+{
+ DescriptorAttributes props;
+ //props[QServiceInterfaceDescriptor::Capabilities] = QStringList();
+ props[QServiceInterfaceDescriptor::Location] = "";
+ props[QServiceInterfaceDescriptor::ServiceDescription] = "";
+ props[QServiceInterfaceDescriptor::InterfaceDescription] = "";
+ return props;
+}
+static const DescriptorAttributes DEFAULT_DESCRIPTOR_PROPERTIES = defaultDescriptorAttributes();
+
+static QStringList validPluginFiles()
+{
+ // these are the plugins under tests/ which point to real service plugins
+ // that can be used for testing (i.e. plugins that can be loaded, invoked)
+ QStringList files;
+ files << "plugins/tst_sfw_sampleserviceplugin" << "plugins/tst_sfw_sampleserviceplugin2";
+ return files;
+}
+static const QStringList VALID_PLUGIN_FILES = validPluginFiles();
+
+// Helper function for debugging. Useful e.g. for checking what is difference between
+// two descriptors (in addition to attributes printed below, the \
+// QServiceInterfaceDescriptor::== operator also compares
+// attributes.
+static void printDescriptor (QServiceInterfaceDescriptor &desc) {
+ qDebug("***QServiceInterfaceDescriptor printed:");
+ qDebug() << "***majorVersion:" << desc.majorVersion();
+ qDebug() << "***minorVersion:" << desc.minorVersion();
+ qDebug() << "***interfaceName:" << desc.interfaceName();
+ qDebug() << "***serviceName:" << desc.serviceName();
+ qDebug() << "***customAttributes:" << desc.customAttributes();
+ qDebug() << "***isValid(): " << desc.isValid();
+ qDebug() << "***scope (user:0, system:1): " << desc.scope();
+}
+
+class MySecuritySession : public QAbstractSecuritySession
+{
+public:
+ MySecuritySession() {}
+ virtual ~MySecuritySession() {}
+
+ virtual bool isAllowed(const QStringList&) { return true; }
+};
+
+class MyServiceContext : public QServiceContext
+{
+public:
+ MyServiceContext() {}
+ ~MyServiceContext() {}
+
+ virtual void notify(ContextType, const QVariant&) {}
+};
+
+
+class ServicesListener : public QObject
+{
+ Q_OBJECT
+public slots:
+ void serviceAdded(const QString &name , QService::Scope scope) {
+ params.append(qMakePair(name, scope));
+ }
+ void serviceRemoved(const QString &name, QService::Scope scope) {
+ params.append(qMakePair(name, scope));
+ }
+public:
+ QList<QPair<QString, QService::Scope> > params;
+};
+
+
+class tst_QServiceManager: public QObject
+{
+ Q_OBJECT
+
+private:
+ QString xmlTestDataPath(const QString &xmlFileName)
+ {
+ // On Symbian applicationDirPath returns application's private directory
+ return QCoreApplication::applicationDirPath() + "/plugins/xmldata/" + xmlFileName;
+ }
+
+ QByteArray createServiceXml(const QString &serviceName, const QByteArray &interfaceXml, const QString &path, const QString &description = QString()) const
+ {
+ QString xml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n";
+ xml += "<service>\n";
+ xml += "<name>" + serviceName + "</name>\n";
+ xml += "<filepath>" + path + "</filepath>\n";
+ xml += "<description>" + description + "</description>\n";
+ xml += interfaceXml;
+ xml += "</service>\n";
+ return xml.toLatin1();
+ }
+
+ QByteArray createServiceXml(const QString &serviceName, const QList<QServiceInterfaceDescriptor> &descriptors) const
+ {
+ Q_ASSERT(descriptors.count() > 0);
+ return createServiceXml(serviceName, createInterfaceXml(descriptors),
+ descriptors[0].attribute(QServiceInterfaceDescriptor::Location).toString(),
+ descriptors[0].attribute(QServiceInterfaceDescriptor::ServiceDescription).toString());
+ }
+
+ QByteArray createInterfaceXml(const QList<QServiceInterfaceDescriptor> &descriptors) const
+ {
+ QByteArray interfacesXml;
+ foreach (const QServiceInterfaceDescriptor &desc, descriptors) {
+ QString version = QString("%1.%2").arg(desc.majorVersion()).arg(desc.minorVersion());
+ interfacesXml += createInterfaceXml(desc.interfaceName(), version,
+ desc.attribute(QServiceInterfaceDescriptor::InterfaceDescription).toString());
+ }
+ return interfacesXml;
+ }
+
+ QByteArray createInterfaceXml(const QString &name, const QString &version = "1.0", const QString &description = QString()) const
+ {
+ QString xml = "<interface>\n";
+ xml += "<name>" + name + "</name>\n";
+ xml += "<version>" + version + "</version>\n";
+ xml += " <description>" + description + "</description>\n";
+ xml += "</interface>\n";
+ return xml.toLatin1();
+
+ }
+
+ QServiceInterfaceDescriptor createDescriptor(const QString &interfaceName, int major, int minor, const QString &serviceName, const DescriptorAttributes &attributes = DescriptorAttributes(), QService::Scope scope = QService::UserScope) const
+ {
+ QString version = QString("%1.%2").arg(major).arg(minor);
+
+ QServiceInterfaceDescriptorPrivate *priv = new QServiceInterfaceDescriptorPrivate;
+ priv->serviceName = serviceName;
+ priv->interfaceName = interfaceName;
+ priv->major = major;
+ priv->minor = minor;
+ priv->scope = scope;
+
+ priv->attributes = attributes;
+ foreach (QServiceInterfaceDescriptor::Attribute key, DEFAULT_DESCRIPTOR_PROPERTIES.keys()) {
+ if (!priv->attributes.contains(key))
+ priv->attributes[key] = DEFAULT_DESCRIPTOR_PROPERTIES[key];
+ }
+
+ QServiceInterfaceDescriptor desc;
+ QServiceInterfaceDescriptorPrivate::setPrivate(&desc, priv);
+ return desc;
+ }
+
+ void deleteTestDatabasesAndWaitUntilDone()
+ {
+ QSfwTestUtil::removeTempUserDb();
+ QSfwTestUtil::removeTempSystemDb();
+
+ QTRY_VERIFY(!QFile::exists(QSfwTestUtil::tempUserDbDir()));
+ QTRY_VERIFY(!QFile::exists(QSfwTestUtil::tempSystemDbDir()));
+ }
+
+private slots:
+ void initTestCase();
+ void cleanupTestCase();
+ void init();
+
+ void constructor();
+ void constructor_scope();
+ void constructor_scope_data();
+
+ void findServices();
+ void findServices_data();
+
+ void findServices_scope();
+ void findServices_scope_data();
+
+ void findInterfaces_filter();
+ void findInterfaces_filter_data();
+
+ void findInterfaces_scope();
+ void findInterfaces_scope_data();
+
+ void loadInterface_string();
+
+ void loadInterface_descriptor();
+ void loadInterface_descriptor_data();
+
+ void loadInterface_testLoadedObjectAttributes();
+
+ void loadLocalTypedInterface();
+
+ void addService();
+ void addService_data();
+
+ void addService_testInvalidServiceXml();
+ void addService_testPluginLoading();
+ void addService_testPluginLoading_data();
+ void addService_testInstallService();
+
+ void removeService();
+
+ void setInterfaceDefault_strings();
+ void setInterfaceDefault_strings_multipleInterfaces();
+
+ void setInterfaceDefault_descriptor();
+ void setInterfaceDefault_descriptor_data();
+
+ void interfaceDefault();
+
+ void serviceAdded();
+ void serviceAdded_data();
+
+ void serviceRemoved();
+ void serviceRemoved_data();
+};
+
+void tst_QServiceManager::initTestCase()
+{
+ qRegisterMetaType<QService::Scope>("QService::Scope");
+
+ QSfwTestUtil::setupTempUserDb();
+ QSfwTestUtil::setupTempSystemDb();
+#if defined(Q_OS_SYMBIAN)
+ QSfwTestUtil::removeDatabases_symbian();
+#endif
+}
+
+void tst_QServiceManager::init()
+{
+#if defined(Q_OS_SYMBIAN)
+ // Wait a millisecond so that QServiceManagers are destroyed and release
+ // the database file (otherwise QFile::remove will get a permission denied -->
+ // in next case, the isEmpty() check fails).
+ QTest::qWait(1);
+#endif
+ QSfwTestUtil::removeTempUserDb();
+ QSfwTestUtil::removeTempSystemDb();
+#if defined(Q_OS_SYMBIAN)
+ QSfwTestUtil::removeDatabases_symbian();
+#endif
+ QSettings settings("com.nokia.qt.serviceframework.tests", "SampleServicePlugin");
+ settings.setValue("installed", false);
+}
+
+void tst_QServiceManager::cleanupTestCase()
+{
+ QSfwTestUtil::removeTempUserDb();
+ QSfwTestUtil::removeTempSystemDb();
+#if defined(Q_OS_SYMBIAN)
+ QSfwTestUtil::removeDatabases_symbian();
+#endif
+ //use QEventLopp::DeferredDeletion
+ //QServiceManager::loadInterface makes use of deleteLater() when
+ //cleaning up service objects and their respective QPluginLoader
+ //we want to force the testcase to run the cleanup code
+ QCoreApplication::processEvents(QEventLoop::AllEvents|QEventLoop::DeferredDeletion);
+}
+
+void tst_QServiceManager::constructor()
+{
+ QObject o;
+ QServiceManager mgr(&o);
+ QCOMPARE(mgr.scope(), QService::UserScope);
+ QCOMPARE(mgr.parent(), &o);
+}
+
+void tst_QServiceManager::constructor_scope()
+{
+ QFETCH(QService::Scope, scope);
+
+ QObject o;
+ QServiceManager mgr(scope, &o);
+ QCOMPARE(mgr.scope(), scope);
+ QCOMPARE(mgr.parent(), &o);
+}
+
+void tst_QServiceManager::constructor_scope_data()
+{
+ QTest::addColumn<QService::Scope>("scope");
+
+ QTest::newRow("user") << QService::UserScope;
+ QTest::newRow("system") << QService::SystemScope;
+}
+
+void tst_QServiceManager::findServices()
+{
+ QFETCH(QList<QByteArray>, xmlBlocks);
+ QFETCH(QStringList, interfaceNames);
+ QFETCH(QSet<QString>, searchByInterfaceResult);
+ QFETCH(QSet<QString>, searchAllResult);
+
+ QServiceManager mgr;
+ QServiceFilter wildcardFilter;
+
+ // Check that nothing is found neither with default search or interface-search
+ QVERIFY(mgr.findServices().isEmpty());
+ foreach (const QString &interface, interfaceNames)
+ QVERIFY(mgr.findServices(interface).isEmpty());
+ QCOMPARE(mgr.findInterfaces(wildcardFilter).count(), 0);
+
+ // Add all services from the xmlBlocks list
+ foreach (const QByteArray &xml, xmlBlocks) {
+ QBuffer buffer;
+ buffer.setData(xml);
+ QVERIFY2(mgr.addService(&buffer), PRINT_ERR(mgr));
+ }
+ // Check that all services are found with default search
+ QCOMPARE(mgr.findServices().toSet(), searchAllResult);
+ // Check that all services are found based on interface search
+ foreach (const QString &interface, interfaceNames)
+ QCOMPARE(mgr.findServices(interface).toSet(), searchByInterfaceResult);
+
+ // Check that nothing is found with empty interface
+ QCOMPARE(mgr.findServices("com.invalid.interface") , QStringList());
+}
+
+void tst_QServiceManager::findServices_data()
+{
+ QTest::addColumn< QList<QByteArray> >("xmlBlocks");
+ QTest::addColumn<QStringList>("interfaceNames");
+ QTest::addColumn< QSet<QString> >("searchByInterfaceResult");
+ QTest::addColumn< QSet<QString> >("searchAllResult");
+
+ QStringList interfaces;
+ interfaces << "com.nokia.qt.TestInterfaceA";
+ interfaces << "com.nokia.qt.TestInterfaceB";
+ QByteArray interfacesXml;
+ for (int i=0; i<interfaces.count(); i++)
+ interfacesXml += "\n" + createInterfaceXml(interfaces[i]);
+
+ QTest::newRow("one service")
+ << (QList<QByteArray>() << createServiceXml("SomeTestService", interfacesXml, VALID_PLUGIN_FILES.first()))
+ << interfaces
+ << (QSet<QString>() << "SomeTestService")
+ << (QSet<QString>() << "SomeTestService");
+
+ QTest::newRow("multiple services with same interfaces")
+ << (QList<QByteArray>() << createServiceXml("SomeTestService", interfacesXml, VALID_PLUGIN_FILES[0])
+ << createServiceXml("SomeSimilarTestService", interfacesXml, VALID_PLUGIN_FILES[1]))
+ << interfaces
+ << (QSet<QString>() << "SomeTestService" << "SomeSimilarTestService")
+ << (QSet<QString>() << "SomeTestService" << "SomeSimilarTestService");
+
+ QStringList interfaces2;
+ interfaces2 << "com.nokia.qt.TestInterfaceY";
+ interfaces2 << "com.nokia.qt.TestInterfaceZ";
+ QByteArray interfacesXml2;
+ for (int i=0; i<interfaces2.count(); i++)
+ interfacesXml2 += "\n" + createInterfaceXml(interfaces2[i]);
+ QTest::newRow("multiple services with different interfaces")
+ << (QList<QByteArray>() << createServiceXml("SomeTestService", interfacesXml, VALID_PLUGIN_FILES[0])
+ << createServiceXml("TestServiceWithOtherInterfaces", interfacesXml2, VALID_PLUGIN_FILES[1]))
+ << interfaces2
+ << (QSet<QString>() << "TestServiceWithOtherInterfaces")
+ << (QSet<QString>() << "SomeTestService" << "TestServiceWithOtherInterfaces");
+}
+
+void tst_QServiceManager::findServices_scope()
+{
+#if defined(Q_OS_SYMBIAN)
+ QSKIP("There is no difference between user and system scope in symbian", SkipAll);
+#endif
+ QFETCH(QService::Scope, scope_add);
+ QFETCH(QService::Scope, scope_find);
+ QFETCH(bool, expectFound);
+
+ QByteArray xml = createServiceXml("SomeTestService",
+ createInterfaceXml("com.nokia.qt.TestInterface"), VALID_PLUGIN_FILES[0]);
+ QBuffer buffer(&xml);
+
+ QServiceManager mgrUser(QService::UserScope);
+ QServiceManager mgrSystem(QService::SystemScope);
+
+ QServiceManager &mgrAdd = scope_add == QService::UserScope ? mgrUser : mgrSystem;
+ QServiceManager &mgrFind = scope_find == QService::UserScope ? mgrUser : mgrSystem;
+
+ QVERIFY2(mgrAdd.addService(&buffer), PRINT_ERR(mgrAdd));
+ QStringList result = mgrFind.findServices();
+ QCOMPARE(!result.isEmpty(), expectFound);
+}
+
+void tst_QServiceManager::findServices_scope_data()
+{
+ QTest::addColumn<QService::Scope>("scope_add");
+ QTest::addColumn<QService::Scope>("scope_find");
+ QTest::addColumn<bool>("expectFound");
+
+ QTest::newRow("user scope")
+ << QService::UserScope << QService::UserScope << true;
+ QTest::newRow("system scope")
+ << QService::SystemScope << QService::SystemScope << true;
+
+ QTest::newRow("user scope - add, system scope - find")
+ << QService::UserScope << QService::SystemScope << false;
+ QTest::newRow("system scope - add, user scope - find")
+ << QService::SystemScope << QService::UserScope << true;
+}
+
+void tst_QServiceManager::findInterfaces_filter()
+{
+ QFETCH(QByteArray, xml);
+ QFETCH(QServiceFilter, filter);
+ QFETCH(QList<QServiceInterfaceDescriptor>, expectedInterfaces);
+
+ QServiceManager mgr;
+
+ QBuffer buffer(&xml);
+ QVERIFY2(mgr.addService(&buffer), PRINT_ERR(mgr));
+
+ QList<QServiceInterfaceDescriptor> result = mgr.findInterfaces(filter);
+ QCOMPARE(result.toSet(), expectedInterfaces.toSet());
+}
+
+void tst_QServiceManager::findInterfaces_filter_data()
+{
+ QTest::addColumn<QByteArray>("xml");
+ QTest::addColumn<QServiceFilter>("filter");
+ QTest::addColumn<ServiceInterfaceDescriptorList>("expectedInterfaces");
+
+ QString serviceName = "SomeTestService";
+ DescriptorAttributes attributes;
+ attributes[QServiceInterfaceDescriptor::Location] = VALID_PLUGIN_FILES.first();
+
+ QList<QServiceInterfaceDescriptor> descriptors;
+ descriptors << createDescriptor("com.nokia.qt.TestInterfaceA", 1, 0, serviceName, attributes);
+ descriptors << createDescriptor("com.nokia.qt.TestInterfaceB", 1, 0, serviceName, attributes);
+ descriptors << createDescriptor("com.nokia.qt.TestInterfaceB", 2, 0, serviceName, attributes);
+ descriptors << createDescriptor("com.nokia.qt.TestInterfaceB", 2, 3, serviceName, attributes);
+
+ QByteArray serviceXml = createServiceXml(serviceName, descriptors);
+ QServiceFilter filter;
+
+ QTest::newRow("empty/wildcard filter")
+ << serviceXml
+ << QServiceFilter()
+ << descriptors;
+
+ filter = QServiceFilter();
+ filter.setInterface("com.nokia.qt.TestInterfaceA");
+ QTest::newRow("by interface name (A)")
+ << serviceXml
+ << filter
+ << descriptors.mid(0, 1);
+
+ filter = QServiceFilter();
+ filter.setInterface("com.nokia.qt.TestInterfaceB");
+ QTest::newRow("by interface name (B)")
+ << serviceXml
+ << filter
+ << descriptors.mid(1);
+
+ filter = QServiceFilter();
+ filter.setServiceName(serviceName);
+ QTest::newRow("by service name, should find all")
+ << serviceXml
+ << filter
+ << descriptors;
+
+ filter = QServiceFilter();
+ filter.setInterface("com.invalid.interface");
+ QTest::newRow("by non-existing interface name")
+ << serviceXml
+ << filter
+ << ServiceInterfaceDescriptorList();
+
+ filter = QServiceFilter();
+ filter.setServiceName("InvalidServiceName");
+ QTest::newRow("by non-existing service name")
+ << serviceXml
+ << filter
+ << ServiceInterfaceDescriptorList();
+
+ //version lookup testing for existing interface
+ //valid from first version onwards
+ filter = QServiceFilter();
+ filter.setInterface("com.nokia.qt.TestInterfaceB", "1.0");
+ QTest::newRow("by version name 1.0 DefaultMatch, should find all B interfaces")
+ << serviceXml
+ << filter
+ << descriptors.mid(1);
+
+ filter = QServiceFilter();
+ filter.setInterface("com.nokia.qt.TestInterfaceB", "1.0", QServiceFilter::MinimumVersionMatch);
+ QTest::newRow("by version name 1.0 MinimumMatch, should find all B interfaces")
+ << serviceXml
+ << filter
+ << descriptors.mid(1);
+
+ filter = QServiceFilter();
+ filter.setInterface("com.nokia.qt.TestInterfaceB", "1.0", QServiceFilter::ExactVersionMatch);
+ QTest::newRow("by version name 1.0 ExactMatch, find B 1.0 only")
+ << serviceXml
+ << filter
+ << descriptors.mid(1, 1);
+
+ //valid with exact version match
+ filter = QServiceFilter();
+ filter.setInterface("com.nokia.qt.TestInterfaceB", "2.0");
+ QTest::newRow("by version name 2.0 DefaultMatch, find B 2.0+")
+ << serviceXml
+ << filter
+ << descriptors.mid(2);
+
+ filter = QServiceFilter();
+ filter.setInterface("com.nokia.qt.TestInterfaceB", "2.0", QServiceFilter::MinimumVersionMatch);
+ QTest::newRow("by version name 2.0 MinimumMatch, find B 2.0+")
+ << serviceXml
+ << filter
+ << descriptors.mid(2);
+
+ filter = QServiceFilter();
+ filter.setInterface("com.nokia.qt.TestInterfaceB", "2.0", QServiceFilter::ExactVersionMatch);
+ QTest::newRow("by version name 2.0 ExactMatch, find B 2.0")
+ << serviceXml
+ << filter
+ << descriptors.mid(2, 1);
+
+ //valid but not exact version match
+ filter = QServiceFilter();
+ filter.setInterface("com.nokia.qt.TestInterfaceB", "1.9");
+ QTest::newRow("by version name 1.9 DefaultMatch, find B 1.9+")
+ << serviceXml
+ << filter
+ << descriptors.mid(2);
+
+ filter = QServiceFilter();
+ filter.setInterface("com.nokia.qt.TestInterfaceB", "1.9", QServiceFilter::MinimumVersionMatch);
+ QTest::newRow("by version name 1.9 MinimumMatch, find B 1.9+")
+ << serviceXml
+ << filter
+ << descriptors.mid(2);
+
+ filter = QServiceFilter();
+ filter.setInterface("com.nokia.qt.TestInterfaceB", "1.9", QServiceFilter::ExactVersionMatch);
+ QTest::newRow("by version name 1.9 ExactMatch")
+ << serviceXml
+ << filter
+ << ServiceInterfaceDescriptorList();
+
+ //version doesn't exist yet
+ filter = QServiceFilter();
+ filter.setInterface("com.nokia.qt.TestInterfaceB", "3.9");
+ QTest::newRow("by version name 3.9 DefaultMatch")
+ << serviceXml
+ << filter
+ << ServiceInterfaceDescriptorList();
+
+ filter = QServiceFilter();
+ filter.setInterface("com.nokia.qt.TestInterfaceB", "3.9", QServiceFilter::MinimumVersionMatch);
+ QTest::newRow("by version name 3.9 MinimumMatch")
+ << serviceXml
+ << filter
+ << ServiceInterfaceDescriptorList();
+
+ filter = QServiceFilter();
+ filter.setInterface("com.nokia.qt.TestInterfaceB", "3.9", QServiceFilter::ExactVersionMatch);
+ QTest::newRow("by version name 3.9 ExactMatch")
+ << serviceXml
+ << filter
+ << ServiceInterfaceDescriptorList();
+
+ //invalid version tag 1 -> match anything
+ filter = QServiceFilter();
+ filter.setInterface("com.nokia.qt.TestInterfaceB", "x3.9");
+ QTest::newRow("by version name x3.9 DefaultMatch")
+ << serviceXml<< filter
+ << descriptors;
+
+ filter = QServiceFilter();
+ filter.setInterface("com.nokia.qt.TestInterfaceB", "x3.9", QServiceFilter::MinimumVersionMatch);
+ QTest::newRow("by version name x3.9 MinimumMatch")
+ << serviceXml
+ << filter
+ << descriptors;
+
+ filter = QServiceFilter();
+ filter.setInterface("com.nokia.qt.TestInterfaceB", "x3.9", QServiceFilter::ExactVersionMatch);
+ QTest::newRow("by version name x3.9 ExactMatch")
+ << serviceXml
+ << filter
+ << descriptors;
+
+ //envalid/empty version tag
+ filter = QServiceFilter();
+ filter.setInterface("com.nokia.qt.TestInterfaceB", "");
+ QTest::newRow("by empty version string DefaultMatch")
+ << serviceXml
+ << filter
+ << descriptors.mid(1);
+
+ filter = QServiceFilter();
+ filter.setInterface("com.nokia.qt.TestInterfaceB", "", QServiceFilter::MinimumVersionMatch);
+ QTest::newRow("by empty version string MinimumMatch")
+ << serviceXml
+ << filter
+ << descriptors.mid(1);
+
+ filter = QServiceFilter();
+ filter.setInterface("com.nokia.qt.TestInterfaceB", "", QServiceFilter::ExactVersionMatch); //what's the result of this?
+ QTest::newRow("by empty version string ExactMatch")
+ << serviceXml
+ << filter
+ << descriptors.mid(1);
+
+ //invalid version tag 2
+ filter = QServiceFilter();
+ filter.setInterface("com.nokia.qt.TestInterfaceB", "abc");
+ QTest::newRow("by version name abc DefaultMatch")
+ << serviceXml<< filter
+ << descriptors;
+
+ filter = QServiceFilter();
+ filter.setInterface("com.nokia.qt.TestInterfaceB", "abc", QServiceFilter::MinimumVersionMatch);
+ QTest::newRow("by version name abc MinimumMatch")
+ << serviceXml<< filter
+ << descriptors;
+
+ filter = QServiceFilter();
+ filter.setInterface("com.nokia.qt.TestInterfaceB", "abc", QServiceFilter::ExactVersionMatch);
+ QTest::newRow("by version name abc ExactMatch")
+ << serviceXml
+ << filter
+ << descriptors;
+}
+
+void tst_QServiceManager::findInterfaces_scope()
+{
+#if defined(Q_OS_SYMBIAN)
+ QSKIP("There is no difference between user and system scope in symbian", SkipAll);
+#endif
+ QFETCH(QService::Scope, scope_add);
+ QFETCH(QService::Scope, scope_find);
+ QFETCH(bool, expectFound);
+
+ QByteArray xml = createServiceXml("SomeTestService",
+ createInterfaceXml("com.nokia.qt.TestInterface"), VALID_PLUGIN_FILES[0]);
+ QBuffer buffer(&xml);
+
+ QServiceManager mgrUser(QService::UserScope);
+ QServiceManager mgrSystem(QService::SystemScope);
+
+ QServiceManager &mgrAdd = scope_add == QService::UserScope ? mgrUser : mgrSystem;
+ QServiceManager &mgrFind = scope_find == QService::UserScope ? mgrUser : mgrSystem;
+
+ QList<QServiceInterfaceDescriptor> result = mgrFind.findInterfaces(QString());
+ QVERIFY(result.isEmpty());
+
+ QVERIFY2(mgrAdd.addService(&buffer), PRINT_ERR(mgrAdd));
+ result = mgrFind.findInterfaces("SomeTestService");
+ QCOMPARE(!result.isEmpty(), expectFound);
+
+ result = mgrFind.findInterfaces(QString());
+ if (expectFound)
+ QVERIFY(result.count() == 1);
+ else
+ QVERIFY(result.isEmpty());
+
+ result = mgrFind.findInterfaces("NonExistingService");
+ QVERIFY(result.isEmpty());
+}
+
+void tst_QServiceManager::findInterfaces_scope_data()
+{
+ findServices_scope_data();
+}
+
+
+void tst_QServiceManager::loadInterface_string()
+{
+ // The sampleservice.xml and sampleservice2.xml services in
+ // tests/sampleserviceplugin and tests/sampleserviceplugin2 implement a
+ // common interface, "com.nokia.qt.TestInterfaceA". If both are
+ // registered, loadInterface(QString) should return the correct one
+ // depending on which is set as the default.
+
+ // Real servicenames and classnames
+ QString serviceA = "SampleService";
+ QString serviceAClassName = "SampleServicePluginClass";
+ QString serviceB = "SampleService2";
+ QString serviceBClassName = "SampleServicePluginClass2";
+
+ QObject *obj = 0;
+ QServiceManager mgr;
+ QString commonInterface = "com.nokia.qt.TestInterfaceA";
+
+ // Add first service. Adds the service described in
+ // c/Private/<uid3 of this executable>/plugins/xmldata/sampleservice.xml
+ QVERIFY2(mgr.addService(xmlTestDataPath("sampleservice.xml")), PRINT_ERR(mgr));
+ obj = mgr.loadInterface(commonInterface, 0, 0);
+ QVERIFY(obj != 0);
+ QCOMPARE(QString(obj->metaObject()->className()), serviceAClassName);
+ delete obj;
+ QCoreApplication::processEvents(QEventLoop::AllEvents|QEventLoop::DeferredDeletion);
+
+ // Add first service. Adds the service described in
+ // c/Private/<uid3 of this executable>/plugins/xmldata/sampleservice2.xml
+ QVERIFY2(mgr.addService(xmlTestDataPath("sampleservice2.xml")), PRINT_ERR(mgr));
+
+ // if first service is set as default, it should be returned
+ QVERIFY(mgr.setInterfaceDefault(serviceA, commonInterface));
+ obj = mgr.loadInterface(commonInterface, 0, 0);
+ QVERIFY(obj != 0);
+ QCOMPARE(QString(obj->metaObject()->className()), serviceAClassName);
+ delete obj;
+ QCoreApplication::processEvents(QEventLoop::AllEvents|QEventLoop::DeferredDeletion);
+
+ // if second service is set as default, it should be returned
+ QVERIFY(mgr.setInterfaceDefault(serviceB, commonInterface));
+ obj = mgr.loadInterface(commonInterface, 0, 0);
+ QVERIFY(obj != 0);
+ QCOMPARE(QString(obj->metaObject()->className()), serviceBClassName);
+ delete obj;
+ QCoreApplication::processEvents(QEventLoop::AllEvents|QEventLoop::DeferredDeletion);
+}
+
+void tst_QServiceManager::loadInterface_descriptor()
+{
+ QFETCH(QServiceInterfaceDescriptor, descriptor);
+ QFETCH(QString, className);
+
+ QObject* obj;
+ {
+ QServiceManager mgr;
+ MySecuritySession session;
+ MyServiceContext context;
+ obj = mgr.loadInterface(descriptor, &context, &session);
+ QVERIFY(obj != 0);
+ QCOMPARE(className, QString(obj->metaObject()->className()));
+ }
+
+ QVERIFY(obj != 0);
+
+ delete obj;
+ QCoreApplication::processEvents(QEventLoop::AllEvents|QEventLoop::DeferredDeletion);
+}
+
+void tst_QServiceManager::loadInterface_descriptor_data()
+{
+ QTest::addColumn<QServiceInterfaceDescriptor>("descriptor");
+ QTest::addColumn<QString>("className");
+
+ QLibrary lib;
+ QServiceInterfaceDescriptor descriptor;
+ QServiceInterfaceDescriptorPrivate *priv = new QServiceInterfaceDescriptorPrivate;
+ priv->interfaceName = "com.nokia.qt.TestInterfaceA"; // needed by service plugin implementation
+
+ lib.setFileName(QCoreApplication::applicationDirPath() + "/plugins/tst_sfw_sampleserviceplugin");
+ QVERIFY(lib.load());
+ QVERIFY(lib.unload());
+#if defined (Q_OS_SYMBIAN)
+ priv->attributes[QServiceInterfaceDescriptor::Location] = "plugins/" + lib.fileName();
+#else
+ priv->attributes[QServiceInterfaceDescriptor::Location] = lib.fileName();
+#endif
+ QServiceInterfaceDescriptorPrivate::setPrivate(&descriptor, priv);
+ QTest::newRow("tst_sfw_sampleserviceplugin")
+ << descriptor
+ << "SampleServicePluginClass";
+
+ lib.setFileName(QCoreApplication::applicationDirPath() + "/plugins/tst_sfw_testservice2plugin");
+ QVERIFY(lib.load());
+ QVERIFY(lib.unload());
+
+#if defined(Q_OS_SYMBIAN)
+ priv->attributes[QServiceInterfaceDescriptor::Location] = "plugins/" + lib.fileName();
+#else
+ priv->attributes[QServiceInterfaceDescriptor::Location] = lib.fileName();
+#endif
+ QServiceInterfaceDescriptorPrivate::setPrivate(&descriptor, priv);
+ QTest::newRow("tst_sfw_sampleserviceplugin2")
+ << descriptor
+ << "TestService";
+}
+
+void tst_QServiceManager::loadInterface_testLoadedObjectAttributes()
+{
+ QLibrary lib(QCoreApplication::applicationDirPath() + "/plugins/tst_sfw_testservice2plugin");
+ QVERIFY(lib.load());
+ QVERIFY(lib.unload());
+
+ QServiceInterfaceDescriptor descriptor;
+ QServiceInterfaceDescriptorPrivate *priv = new QServiceInterfaceDescriptorPrivate;
+ priv->interfaceName = "com.nokia.qt.TestInterfaceA"; // needed by service plugin implementation
+#if defined(Q_OS_SYMBIAN)
+ priv->attributes[QServiceInterfaceDescriptor::Location] = "plugins/" + lib.fileName();
+#else
+ priv->attributes[QServiceInterfaceDescriptor::Location] = lib.fileName();
+#endif
+ QServiceInterfaceDescriptorPrivate::setPrivate(&descriptor, priv);
+
+ QServiceManager mgr;
+ MySecuritySession session;
+ MyServiceContext context;
+ QObject *obj = mgr.loadInterface(descriptor, &context, &session);
+ QVERIFY(obj != 0);
+
+ bool invokeOk = false;
+ QString name;
+
+ // check attributes
+ QMetaProperty nameProperty = obj->metaObject()->property(obj->metaObject()->indexOfProperty("name"));
+ QVERIFY(nameProperty.isValid());
+ QVERIFY(nameProperty.write(obj, "A service name"));
+ QCOMPARE(nameProperty.read(obj), QVariant("A service name"));
+
+ // check signals
+ QVERIFY(obj->metaObject()->indexOfSignal("someSignal()") >= 0);
+ QSignalSpy spy(obj, SIGNAL(someSignal()));
+ invokeOk = QMetaObject::invokeMethod(obj, "someSignal");
+ QVERIFY(invokeOk);
+ QVERIFY(spy.count() == 1);
+
+ // check slots
+ invokeOk = QMetaObject::invokeMethod(obj, "callSlot");
+ QVERIFY(invokeOk);
+ invokeOk = QMetaObject::invokeMethod(obj, "callSlotAndSetName", Q_ARG(QString, "test string"));
+ QVERIFY(invokeOk);
+ invokeOk = QMetaObject::invokeMethod(obj, "callSlotAndReturnName", Q_RETURN_ARG(QString, name));
+ QVERIFY(invokeOk);
+ QCOMPARE(name, QString("test string"));
+
+ // check invokables
+ invokeOk = QMetaObject::invokeMethod(obj, "callInvokable");
+ QVERIFY(invokeOk);
+
+ // call method on a returned object
+ QObject *embeddedObj = 0;
+ int value = 0;
+ invokeOk = QMetaObject::invokeMethod(obj, "embeddedTestService", Q_RETURN_ARG(QObject*, embeddedObj));
+ QVERIFY(invokeOk);
+ invokeOk = QMetaObject::invokeMethod(embeddedObj, "callWithInt", Q_RETURN_ARG(int, value), Q_ARG(int, 10));
+ QVERIFY(invokeOk);
+ QCOMPARE(value, 10);
+
+ // call a method that is not invokable via meta system
+ invokeOk = QMetaObject::invokeMethod(embeddedObj, "callNormalMethod");
+ QVERIFY(!invokeOk);
+
+ delete obj;
+ QCoreApplication::processEvents(QEventLoop::AllEvents|QEventLoop::DeferredDeletion);
+}
+
+void tst_QServiceManager::loadLocalTypedInterface()
+{
+ //ensure the plugin exists
+ QLibrary lib(QCoreApplication::applicationDirPath() + "/plugins/tst_sfw_sampleserviceplugin");
+ QCOMPARE(lib.load(), true);
+ lib.unload();
+
+ QServiceManager mgr;
+ MySecuritySession session;
+ MyServiceContext context;
+
+ QServiceInterfaceDescriptor descriptor;
+ QServiceInterfaceDescriptorPrivate *priv = new QServiceInterfaceDescriptorPrivate;
+ priv->interfaceName = "com.nokia.qt.TestInterfaceA"; // needed by service plugin implementation
+#if defined(Q_OS_SYMBIAN)
+ priv->attributes[QServiceInterfaceDescriptor::Location] = "plugins/" + lib.fileName();
+#else
+ priv->attributes[QServiceInterfaceDescriptor::Location] = lib.fileName();
+#endif
+ QServiceInterfaceDescriptorPrivate::setPrivate(&descriptor, priv);
+
+ //use manual descriptor -> avoid database involvement
+ SampleServicePluginClass *plugin = 0;
+ plugin = mgr.loadLocalTypedInterface<SampleServicePluginClass>(descriptor, &context, &session);
+
+ QVERIFY(plugin != 0);
+ QCOMPARE(plugin->context(), (QServiceContext *)&context);
+ QCOMPARE(plugin->securitySession(), (QAbstractSecuritySession *)&session);
+
+ delete plugin;
+ plugin = 0;
+ QCoreApplication::processEvents(QEventLoop::AllEvents|QEventLoop::DeferredDeletion);
+
+ //use database descriptor
+ QFile file1(xmlTestDataPath("sampleservice.xml"));
+ QVERIFY(file1.exists());
+ QVERIFY2(mgr.addService(&file1), PRINT_ERR(mgr));
+
+ QCOMPARE(mgr.findServices("com.nokia.qt.TestInterfaceA"), QStringList("SampleService"));
+ QCOMPARE(mgr.findServices("com.nokia.qt.TestInterfaceB"), QStringList("SampleService"));
+ QCOMPARE(mgr.findServices("com.nokia.qt.TestInterfaceC"), QStringList("SampleService"));
+ QList<QServiceInterfaceDescriptor> ifaces = mgr.findInterfaces("SampleService");
+ QList<SampleServicePluginClass*> serviceObjects;
+ QVERIFY(ifaces.count() == 3);
+ for (int i = 0; i<ifaces.count(); i++) {
+ plugin = mgr.loadLocalTypedInterface<SampleServicePluginClass>(ifaces.at(i), &context, &session);
+
+ if (ifaces.at(i).interfaceName() == "com.nokia.qt.TestInterfaceC") {
+ QVERIFY(plugin == 0);
+ } else {
+ QVERIFY(plugin != 0);
+ QCOMPARE(plugin->context(), (QServiceContext *)&context);
+ QCOMPARE(plugin->securitySession(), (QAbstractSecuritySession *)&session);
+ plugin->testSlotOne();
+ serviceObjects.append(plugin);
+ }
+ }
+
+ //test for a bug where two service instances from same plugin
+ //caused a crash when the first instance was deleted and
+ //the second instance called
+ QVERIFY(serviceObjects.count() == 2);
+ delete serviceObjects.takeFirst();
+ QCoreApplication::processEvents(QEventLoop::AllEvents|QEventLoop::DeferredDeletion);
+
+ plugin = serviceObjects.takeFirst();
+ plugin->testSlotOne();
+ delete plugin;
+ QCoreApplication::processEvents(QEventLoop::AllEvents|QEventLoop::DeferredDeletion);
+
+
+ //use default lookup
+ plugin = mgr.loadLocalTypedInterface<SampleServicePluginClass>("com.nokia.qt.TestInterfaceA", &context, &session);
+ QVERIFY(plugin != 0);
+ QCOMPARE(plugin->context(), (QServiceContext *)&context);
+ QCOMPARE(plugin->securitySession(), (QAbstractSecuritySession *)&session);
+
+ delete plugin;
+ QCoreApplication::processEvents(QEventLoop::AllEvents|QEventLoop::DeferredDeletion);
+ plugin = 0;
+
+ //use totally wrong but QObject based template class type
+ QFile *w = mgr.loadLocalTypedInterface<QFile>("com.nokia.qt.TestInterfaceA", &context, &session);
+ QVERIFY(!w);
+
+ //use non QObject based template class type
+ //doesn't compile and should never compile
+ //QString* s = mgr.loadLocalTypedInterface<QString>("com.nokia.qt.TestInterfaceA", &context, &session);
+ //QVERIFY(!s);
+}
+
+#define TST_QSERVICEMANAGER_ADD_SERVICE(paramType, file) { \
+ if (paramType == "QString") \
+ QVERIFY2(mgr.addService(file->fileName()), PRINT_ERR(mgr)); \
+ else if (paramType == "QIODevice") \
+ QVERIFY2(mgr.addService(file), PRINT_ERR(mgr)); \
+ else \
+ QFAIL("tst_QServiceManager::addService(): Bad test parameter"); \
+}
+
+void tst_QServiceManager::addService()
+{
+ QFETCH(QString, paramType);
+
+ QServiceManager mgr;
+
+ QString commonInterface = "com.qt.serviceframework.tests.CommonInterface";
+ QByteArray xmlA = createServiceXml("ServiceA", createInterfaceXml(commonInterface), VALID_PLUGIN_FILES[0]);
+ QByteArray xmlB = createServiceXml("ServiceB", createInterfaceXml(commonInterface), VALID_PLUGIN_FILES[1]);
+
+ QTemporaryFile *tempFileA = new QTemporaryFile(this);
+ QVERIFY2(tempFileA->open(), "Can't open temp file A");
+ tempFileA->write(xmlA);
+ tempFileA->seek(0);
+ QTemporaryFile *tempFileB = new QTemporaryFile(this);
+ QVERIFY2(tempFileB->open(), "Can't open temp file B");
+ tempFileB->write(xmlB);
+ tempFileB->seek(0);
+
+ TST_QSERVICEMANAGER_ADD_SERVICE(paramType, tempFileA);
+ QCOMPARE(mgr.findServices(), QStringList("ServiceA"));
+
+ // the service should be automatically set as the default for its
+ // implemented interfaces since it was the first service added for them
+ QCOMPARE(mgr.interfaceDefault(commonInterface).serviceName(), QString("ServiceA"));
+ QCOMPARE(mgr.interfaceDefault(commonInterface).serviceName(), QString("ServiceA"));
+
+ // add second service
+ TST_QSERVICEMANAGER_ADD_SERVICE(paramType, tempFileB);
+ QStringList result = mgr.findServices();
+ QCOMPARE(result.count(), 2);
+ QVERIFY(result.contains("ServiceA"));
+ QVERIFY(result.contains("ServiceB"));
+
+ // the default does not change once ServiceB is added
+ QCOMPARE(mgr.interfaceDefault(commonInterface).serviceName(), QString("ServiceA"));
+ QCOMPARE(mgr.interfaceDefault(commonInterface).serviceName(), QString("ServiceA"));
+
+ delete tempFileA;
+ delete tempFileB;
+}
+
+void tst_QServiceManager::addService_data()
+{
+ QTest::addColumn<QString>("paramType");
+
+ QTest::newRow("string") << "QString";
+ QTest::newRow("iodevice") << "QIODevice";
+}
+
+void tst_QServiceManager::addService_testInvalidServiceXml()
+{
+ QBuffer buffer;
+ QServiceManager mgr;
+
+ QVERIFY2(!mgr.addService(&buffer), PRINT_ERR(mgr));
+
+ // a service with no interfaces
+ QString xml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n";
+ xml += "<service><name>SomeService</name><filepath>" + VALID_PLUGIN_FILES.first() + "</filepath>\n";
+ xml += "</service>\n";
+ buffer.close();
+ buffer.setData(xml.toLatin1());
+ QVERIFY(!mgr.addService(&buffer));
+
+ QVERIFY2(mgr.findServices().isEmpty(), PRINT_ERR(mgr));
+}
+
+void tst_QServiceManager::addService_testPluginLoading()
+{
+ QFETCH(QString, pluginPath);
+ QFETCH(bool, isAdded);
+
+ QServiceManager mgr;
+
+ QByteArray xml = createServiceXml("SomeService", createInterfaceXml("com.qt.serviceframework.Interface"), pluginPath);
+ QBuffer buffer(&xml);
+ QVERIFY2(mgr.addService(&buffer) == isAdded, PRINT_ERR(mgr));
+
+ // the service should not be added if the service plugin cannot be loaded
+ if (!isAdded)
+ QVERIFY(mgr.findServices().isEmpty());
+}
+
+void tst_QServiceManager::addService_testPluginLoading_data()
+{
+ QTest::addColumn<QString>("pluginPath");
+ QTest::addColumn<bool>("isAdded");
+
+ QTest::newRow("valid path") << VALID_PLUGIN_FILES.first() << true;
+ QTest::newRow("invalid path") << "no_such_plugin" << false;
+}
+
+void tst_QServiceManager::addService_testInstallService()
+{
+ QSettings settings("com.nokia.qt.serviceframework.tests", "SampleServicePlugin");
+ QCOMPARE(settings.value("installed").toBool(), false);
+
+ QServiceManager mgr;
+ QVERIFY2(mgr.addService(xmlTestDataPath("sampleservice.xml")), PRINT_ERR(mgr));
+ QCOMPARE(mgr.findServices(), QStringList("SampleService"));
+
+ // test installService() was called on the plugin
+ QCOMPARE(settings.value("installed").toBool(), true);
+}
+
+void tst_QServiceManager::removeService()
+{
+ QServiceManager mgr;
+
+ QVERIFY(!mgr.removeService("NonExistentService"));
+
+ QSettings settings("com.nokia.qt.serviceframework.tests", "SampleServicePlugin");
+ QCOMPARE(settings.value("installed").toBool(), false);
+
+ QVERIFY2(mgr.addService(xmlTestDataPath("sampleservice.xml")), PRINT_ERR(mgr));
+ QCOMPARE(mgr.findServices("com.nokia.qt.TestInterfaceA"), QStringList("SampleService"));
+ QCOMPARE(settings.value("installed").toBool(), true);
+
+ QVERIFY(mgr.removeService("SampleService"));
+ QVERIFY(mgr.findServices().isEmpty());
+ QCOMPARE(mgr.findServices("com.nokia.qt.TestInterfaceA"), QStringList());
+ QCOMPARE(settings.value("installed").toBool(), false);
+
+ // add it again, should still work
+ QVERIFY2(mgr.addService(xmlTestDataPath("sampleservice.xml")), PRINT_ERR(mgr));
+ QCOMPARE(mgr.findServices("com.nokia.qt.TestInterfaceA"), QStringList("SampleService"));
+ QCOMPARE(settings.value("installed").toBool(), true);
+}
+
+void tst_QServiceManager::setInterfaceDefault_strings()
+{
+ QServiceManager mgr;
+ QString interfaceName = "com.nokia.qt.serviceframework.tests.AnInterface";
+ DescriptorAttributes attributes;
+ QServiceInterfaceDescriptor descriptor;
+ QByteArray xml;
+
+ attributes[QServiceInterfaceDescriptor::Location] = VALID_PLUGIN_FILES[0];
+ descriptor = createDescriptor(interfaceName, 1, 0, "ServiceA", attributes);
+ xml = createServiceXml("ServiceA",
+ createInterfaceXml(QList<QServiceInterfaceDescriptor>() << descriptor),
+ attributes[QServiceInterfaceDescriptor::Location].toString());
+ QBuffer buffer(&xml);
+
+ // fails if the specified interface hasn't been registered
+ QCOMPARE(mgr.setInterfaceDefault("ServiceA", interfaceName), false);
+
+ // now it works
+ QVERIFY2(mgr.addService(&buffer), PRINT_ERR(mgr));
+ QCOMPARE(mgr.setInterfaceDefault("ServiceA", interfaceName), true);
+ QCOMPARE(mgr.interfaceDefault(interfaceName), descriptor);
+
+ // replace the default with another service
+ attributes[QServiceInterfaceDescriptor::Location] = VALID_PLUGIN_FILES[1];
+ descriptor = createDescriptor(interfaceName, 1, 0, "ServiceB", attributes);
+ xml = createServiceXml("ServiceB",
+ createInterfaceXml(QList<QServiceInterfaceDescriptor>() << descriptor),
+ attributes[QServiceInterfaceDescriptor::Location].toString());
+ buffer.close();
+ buffer.setData(xml);
+ QVERIFY2(mgr.addService(&buffer), PRINT_ERR(mgr));
+ QCOMPARE(mgr.setInterfaceDefault("ServiceB", interfaceName), true);
+ QCOMPARE(mgr.interfaceDefault(interfaceName), descriptor);
+
+ // bad arguments
+ QCOMPARE(mgr.setInterfaceDefault("", ""), false);
+ QCOMPARE(mgr.setInterfaceDefault("blah", "blah"), false);
+ QCOMPARE(mgr.setInterfaceDefault("SampleService", ""), false);
+}
+
+void tst_QServiceManager::setInterfaceDefault_strings_multipleInterfaces()
+{
+ QServiceManager mgr;
+ QString interfaceName = "com.nokia.qt.serviceframework.tests.AnInterface";
+ DescriptorAttributes attributes;
+ QServiceInterfaceDescriptor descriptor;
+ QByteArray xml;
+
+ // if there are multiple interfaces, the default should be the latest version
+ attributes[QServiceInterfaceDescriptor::Location] = VALID_PLUGIN_FILES[0];
+ QList<QServiceInterfaceDescriptor> descriptorList;
+ descriptorList << createDescriptor(interfaceName, 1, 0, "ServiceC", attributes)
+ << createDescriptor(interfaceName, 1, 8, "ServiceC", attributes)
+ << createDescriptor(interfaceName, 1, 3, "ServiceC", attributes);
+ xml = createServiceXml("ServiceC", createInterfaceXml(descriptorList),
+ attributes[QServiceInterfaceDescriptor::Location].toString());
+ QBuffer buffer(&xml);
+ QVERIFY2(mgr.addService(&buffer), PRINT_ERR(mgr));
+ QCOMPARE(mgr.setInterfaceDefault("ServiceC", interfaceName), true);
+ QCOMPARE(mgr.interfaceDefault(interfaceName), descriptorList[1]);
+}
+
+void tst_QServiceManager::setInterfaceDefault_descriptor()
+{
+ QFETCH(QService::Scope, scope_add);
+ QFETCH(QService::Scope, scope_find);
+ QFETCH(bool, expectFound);
+
+ QServiceManager mgr(scope_add);
+ QServiceInterfaceDescriptor desc;
+
+ QString interfaceName = "com.nokia.qt.serviceframework.TestInterface";
+ DescriptorAttributes attributes;
+ attributes[QServiceInterfaceDescriptor::Location] = VALID_PLUGIN_FILES.first();
+
+ QCOMPARE(mgr.setInterfaceDefault(desc), false);
+
+ desc = createDescriptor(interfaceName, 1, 0, "SomeService", attributes,
+ scope_add);
+
+ // fails if the specified interface hasn't been registered
+ QCOMPARE(mgr.setInterfaceDefault(desc), false);
+
+ // now it works
+ QByteArray xml = createServiceXml("SomeService",
+ createInterfaceXml(QList<QServiceInterfaceDescriptor>() << desc), VALID_PLUGIN_FILES.first());
+ QBuffer buffer(&xml);
+ QVERIFY2(mgr.addService(&buffer), PRINT_ERR(mgr));
+ QCOMPARE(mgr.setInterfaceDefault(desc), true);
+
+ QCOMPARE(mgr.interfaceDefault(interfaceName), desc);
+
+#if defined(Q_OS_SYMBIAN)
+ QCOMPARE(mgr.interfaceDefault(interfaceName).isValid(), expectFound);
+#else
+ QServiceManager mgrWithOtherScope(scope_find);
+ QCOMPARE(mgrWithOtherScope.interfaceDefault(interfaceName).isValid(), expectFound);
+#endif
+}
+
+void tst_QServiceManager::setInterfaceDefault_descriptor_data()
+{
+ QTest::addColumn<QService::Scope>("scope_add");
+ QTest::addColumn<QService::Scope>("scope_find");
+ QTest::addColumn<bool>("expectFound");
+
+#if defined(Q_OS_SYMBIAN)
+ // Symbian implementation hard-codes user-scope for everything, do not test any system scope-stuff
+ // because returned service interface descriptor is always in user-scope
+ QTest::newRow("user scope")
+ << QService::UserScope << QService::UserScope << true;
+#else
+ QTest::newRow("user scope")
+ << QService::UserScope << QService::UserScope << true;
+ QTest::newRow("system scope")
+ << QService::SystemScope << QService::SystemScope << true;
+
+ QTest::newRow("user scope - add, system scope - find")
+ << QService::UserScope << QService::SystemScope << false;
+ QTest::newRow("system scope - add, user scope - find")
+ << QService::SystemScope << QService::UserScope << true;
+#endif /* Q_OS_SYMBIAN */
+}
+
+void tst_QServiceManager::interfaceDefault()
+{
+ QServiceManager mgr;
+ QVERIFY(!mgr.interfaceDefault("").isValid());
+}
+
+void tst_QServiceManager::serviceAdded()
+{
+ QFETCH(QByteArray, xml);
+ QFETCH(QString, serviceName);
+ QFETCH(QService::Scope, scope_modify);
+ QFETCH(QService::Scope, scope_listen);
+ QFETCH(bool, expectSignal);
+
+ QBuffer buffer;
+ buffer.setData(xml);
+ QServiceManager mgr_modify(scope_modify);
+ QServiceManager mgr_listen(scope_listen);
+
+ // ensure mgr.connectNotify() is called
+ ServicesListener *listener = new ServicesListener;
+ connect(&mgr_listen, SIGNAL(serviceAdded(QString,QService::Scope)),
+ listener, SLOT(serviceAdded(QString,QService::Scope)));
+
+ QSignalSpy spyAdd(&mgr_listen, SIGNAL(serviceAdded(QString,QService::Scope)));
+ QVERIFY2(mgr_modify.addService(&buffer), PRINT_ERR(mgr_modify));
+
+ if (!expectSignal) {
+ QTest::qWait(2000);
+ QCOMPARE(spyAdd.count(), 0);
+ } else {
+ QTRY_COMPARE(spyAdd.count(), 1);
+ }
+
+ if (expectSignal) {
+ QCOMPARE(spyAdd.at(0).at(0).toString(), serviceName);
+ QCOMPARE( listener->params.at(0).second , scope_modify);
+ }
+ listener->params.clear();
+
+ // Pause between file changes so they are detected separately
+ QTest::qWait(2000);
+
+ QSignalSpy spyRemove(&mgr_listen, SIGNAL(serviceRemoved(QString,QService::Scope)));
+ QVERIFY(mgr_modify.removeService(serviceName));
+
+ if (!expectSignal) {
+ QTest::qWait(2000);
+ QCOMPARE(spyRemove.count(), 0);
+ } else {
+ QTRY_COMPARE(spyRemove.count(), 1);
+ }
+
+#if !defined (Q_OS_WIN) && !defined (Q_OS_SYMBIAN)
+ // on win and symbian, cannot delete the database while it is in use
+ // try it again after deleting the database
+ deleteTestDatabasesAndWaitUntilDone();
+#else
+ // Pause between file changes so they are detected separately
+ QTest::qWait(2000);
+#endif
+
+ spyAdd.clear();
+ buffer.seek(0);
+ QVERIFY2(mgr_modify.addService(&buffer), PRINT_ERR(mgr_modify));
+ if (!expectSignal) {
+ QTest::qWait(2000);
+ QCOMPARE(spyAdd.count(), 0);
+ } else {
+ QTRY_COMPARE(spyAdd.count(), 1);
+ }
+ if (expectSignal) {
+ QCOMPARE(spyAdd.at(0).at(0).toString(), serviceName);
+ QCOMPARE(listener->params.at(0).second, scope_modify);
+ }
+
+ // ensure mgr.disconnectNotify() is called
+ disconnect(&mgr_listen, SIGNAL(serviceRemoved(QString,QService::Scope)),
+ listener, SLOT(serviceRemoved(QString,QService::Scope)));
+
+ delete listener;
+}
+
+void tst_QServiceManager::serviceAdded_data()
+{
+ QTest::addColumn<QByteArray>("xml");
+ QTest::addColumn<QString>("serviceName");
+ QTest::addColumn<QService::Scope>("scope_modify");
+ QTest::addColumn<QService::Scope>("scope_listen");
+ QTest::addColumn<bool>("expectSignal");
+
+ QFile file1(xmlTestDataPath("sampleservice.xml"));
+ QVERIFY(file1.open(QIODevice::ReadOnly));
+ QFile file2(xmlTestDataPath("testserviceplugin.xml"));
+ QVERIFY(file2.open(QIODevice::ReadOnly));
+
+ QByteArray file1Data = file1.readAll();
+
+#if defined (Q_OS_SYMBIAN)
+ // Symbian implementation hard-codes (ignores) scopes for everything, do not test mixed-scope stuff
+ QTest::newRow("SampleService, user scope") << file1Data << "SampleService"
+ << QService::SystemScope << QService::SystemScope << true;
+ QTest::newRow("TestService, user scope") << file2.readAll() << "TestService"
+ << QService::SystemScope << QService::SystemScope << true;
+#else
+ QTest::newRow("SampleService, user scope") << file1Data << "SampleService"
+ << QService::UserScope << QService::UserScope << true;
+ QTest::newRow("TestService, user scope") << file2.readAll() << "TestService"
+ << QService::UserScope << QService::UserScope << true;
+
+ QTest::newRow("system scope") << file1Data << "SampleService"
+ << QService::SystemScope << QService::SystemScope << true;
+ QTest::newRow("modify as user, listen in system") << file1Data << "SampleService"
+ << QService::UserScope << QService::SystemScope << false;
+ QTest::newRow("modify as system, listen in user") << file1Data << "SampleService"
+ << QService::SystemScope << QService::UserScope << true;
+#endif /* Q_OS_SYMBIAN */
+}
+
+void tst_QServiceManager::serviceRemoved()
+{
+ QFETCH(QByteArray, xml);
+ QFETCH(QString, serviceName);
+ QFETCH(QService::Scope, scope_modify);
+ QFETCH(QService::Scope, scope_listen);
+ QFETCH(bool, expectSignal);
+
+ QBuffer buffer;
+ buffer.setData(xml);
+ QServiceManager mgr_modify(scope_modify);
+ QServiceManager mgr_listen(scope_listen);
+
+ // ensure mgr.connectNotify() is called
+ ServicesListener *listener = new ServicesListener;
+ connect(&mgr_listen, SIGNAL(serviceRemoved(QString,QService::Scope)),
+ listener, SLOT(serviceRemoved(QString,QService::Scope)));
+
+ QSignalSpy spyAdd(&mgr_listen, SIGNAL(serviceAdded(QString,QService::Scope)));
+ QVERIFY2(mgr_modify.addService(&buffer), PRINT_ERR(mgr_modify));
+
+ if (!expectSignal) {
+ QTest::qWait(2000);
+ QCOMPARE(spyAdd.count(), 0);
+ } else {
+ QTRY_COMPARE(spyAdd.count(), 1);
+ }
+
+ // Pause between file changes so they are detected separately
+ QTest::qWait(2000);
+
+
+ QSignalSpy spyRemove(&mgr_listen, SIGNAL(serviceRemoved(QString,QService::Scope)));
+ QVERIFY(mgr_modify.removeService(serviceName));
+
+ if (!expectSignal) {
+ QTest::qWait(2000);
+ QCOMPARE(spyRemove.count(), 0);
+ } else {
+ QTRY_COMPARE(spyRemove.count(), 1);
+ }
+ if (expectSignal) {
+ QCOMPARE(spyRemove.at(0).at(0).toString(), serviceName);
+ QCOMPARE(listener->params.at(0).second , scope_modify);
+ }
+ listener->params.clear();
+
+#if !defined (Q_OS_WIN) && !defined (Q_OS_SYMBIAN)
+ // on win and symbian, cannot delete the database while it is in use
+ // try it again after deleting the database
+ deleteTestDatabasesAndWaitUntilDone();
+#else
+ // Pause between file changes so they are detected separately
+ QTest::qWait(2000);
+#endif
+ spyAdd.clear();
+ buffer.seek(0);
+ QVERIFY2(mgr_modify.addService(&buffer), PRINT_ERR(mgr_modify));
+ if (!expectSignal) {
+ QTest::qWait(2000);
+ QCOMPARE(spyAdd.count(), 0);
+ } else {
+ QTRY_COMPARE(spyAdd.count(), 1);
+ }
+
+ spyRemove.clear();
+
+ // Pause between file changes so they are detected separately
+ QTest::qWait(2000);
+
+ QVERIFY(mgr_modify.removeService(serviceName));
+ if (!expectSignal) {
+ QTest::qWait(2000);
+ QCOMPARE(spyRemove.count(), 0);
+ } else {
+ QTRY_COMPARE(spyRemove.count(), 1);
+ }
+ if (expectSignal) {
+ QCOMPARE(spyRemove.at(0).at(0).toString(), serviceName);
+ QCOMPARE(listener->params.at(0).second , scope_modify);
+ }
+
+ // ensure mgr.disconnectNotify() is called
+ disconnect(&mgr_listen, SIGNAL(serviceRemoved(QString,QService::Scope)),
+ listener, SLOT(serviceRemoved(QString,QService::Scope)));
+
+ delete listener;
+}
+
+void tst_QServiceManager::serviceRemoved_data()
+{
+ serviceAdded_data();
+}
+
+QTEST_MAIN(tst_QServiceManager)
+
+#include "tst_qservicemanager.moc"