--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/auto/qvaluespacesubscriber/tst_qvaluespacesubscribershared.cpp Wed Aug 25 15:49:42 2010 +0300
@@ -0,0 +1,1244 @@
+/****************************************************************************
+**
+** 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 "tst_qvaluespacesubscribershared.h"
+
+#include <qvaluespacesubscriber.h>
+#include <qvaluespacepublisher.h>
+#include <qvaluespacemanager_p.h>
+
+#include <QTest>
+#include <QSet>
+#include <QSignalSpy>
+#include <QProcess>
+#include <QFile>
+#include <QThread>
+#include <QTimer>
+#include <math.h>
+
+#include <QDebug>
+
+#ifdef Q_OS_WIN
+#define _WIN32_WINNT 0x0500
+#include <windows.h>
+#endif
+
+#define ERROR_SETVALUE_NOT_SUPPORTED 1
+
+#if defined(Q_OS_SYMBIAN)// || defined (Q_OS_LINUX)
+ #define QTRY_COMPARE(a,e) \
+ for (int _i = 0; _i < 100; _i++) { \
+ if ((a) == (e)) break; \
+ QTest::qWait(1); \
+ } \
+ QCOMPARE(a, e)
+
+ #define QTRY_VERIFY(a) \
+ for (int _i = 0; _i < 100; _i ++) { \
+ if (a) break; \
+ QTest::qWait(1); \
+ } \
+ QVERIFY(a)
+#else
+ #define QTRY_COMPARE(a,e) \
+ for (int _i = 0; _i < 10000; _i += 100) { \
+ if ((a) == (e)) break; \
+ QTest::qWait(100); \
+ } \
+ QCOMPARE(a, e)
+
+ #define QTRY_VERIFY(a) \
+ for (int _i = 0; _i < 10000; _i += 100) { \
+ if (a) break; \
+ QTest::qWait(100); \
+ } \
+ QVERIFY(a)
+#endif
+QTM_USE_NAMESPACE
+class ChangeListener : public QObject
+{
+ Q_OBJECT
+
+Q_SIGNALS:
+ void baseChanged();
+ void interestChanged(const QString&, bool);
+};
+
+Q_DECLARE_METATYPE(QValueSpaceSubscriber*)
+Q_DECLARE_METATYPE(QAbstractValueSpaceLayer*)
+Q_DECLARE_METATYPE(QVariant)
+Q_DECLARE_METATYPE(QValueSpace::LayerOptions)
+Q_DECLARE_METATYPE(QUuid)
+
+void tst_QValueSpaceSubscriber::initTestCase()
+{
+ qRegisterMetaType<QVariant>("QVariant");
+ qRegisterMetaType<QValueSpace::LayerOptions>("QValueSpace::LayerOptions");
+
+#ifdef Q_OS_WIN
+ HKEY key;
+ long result = RegOpenKeyEx(HKEY_CURRENT_USER, L"Software\\Nokia",
+ 0, KEY_ALL_ACCESS, &key);
+ if (result == ERROR_SUCCESS) {
+ result = RegDeleteKey(key, L"QtMobility\\volatileContext");
+ result = RegDeleteKey(key, L"QtMobility\\nonVolatileContext");
+ result = RegDeleteKey(key, L"QtMobility");
+
+ RegCloseKey(key);
+ }
+#endif
+
+#if defined(Q_OS_UNIX) && defined(QT_START_VALUESPACE)
+ QFile::remove("/tmp/qt-0/valuespace_shmlayer");
+#endif
+
+#if defined(QT_START_VALUESPACE)
+ QValueSpace::initValueSpaceServer();
+#endif
+
+ QList<QAbstractValueSpaceLayer *> layers = QValueSpaceManager::instance()->getLayers();
+ for (int i = 0; i < layers.count(); ++i) {
+ QValueSpacePublisher *root = new QValueSpacePublisher(layers.at(i)->id(), "/");
+ root->setValue("/home/user/bool", true);
+ root->setValue("/home/user/int", 3);
+ root->setValue("/home/user/QString", QString("testString"));
+ QStringList stringList;
+ stringList << QString("String 1") << QString("String 2");
+ root->setValue("/home/user/QStringList", stringList);
+ root->setValue("/home/user/qint64", qint64(64));
+ root->setValue("/home/user/QByteArray", QByteArray("testByteArray"));
+ root->setValue("/home/user/double", 4.56);
+ root->setValue("/home/user/float", (float)4.56f);
+ root->setValue("/home/user/QChar", QChar('c'));
+ //so far not a lot of data types are supported
+ //root->setValue("/home/user/QRect", QRect(0,0,5,6));
+
+ root->setValue("/home/usercount", 1);
+
+ root->setValue("/layer/name", layers.at(i)->name());
+ root->setValue("/layer/id", layers.at(i)->id().toString());
+ root->setValue("/layer/options", uint(layers.at(i)->layerOptions()));
+
+ root->sync();
+
+ roots.insert(layers.at(i), root);
+
+ QValueSpacePublisher *busy = new QValueSpacePublisher(layers.at(i)->id(), "/usr");
+ busy->setValue("alex/busy", true);
+ busy->setValue("lorn/busy", false);
+ busy->sync();
+
+ busys.insert(layers.at(i), busy);
+ }
+}
+
+void tst_QValueSpaceSubscriber::cleanupTestCase()
+{
+ foreach (QAbstractValueSpaceLayer *layer, roots.keys()) {
+ QValueSpacePublisher *root = roots.take(layer);
+
+ if (layer->layerOptions() & QValueSpace::PermanentLayer) {
+ root->resetValue("/home/user/bool");
+ root->resetValue("/home/user/int");
+ root->resetValue("/home/user/QString");
+ root->resetValue("/home/user/QStringList");
+ root->resetValue("/home/user/qint64");
+ root->resetValue("/home/user/QByteArray");
+ root->resetValue("/home/user/double");
+ root->resetValue("/home/user/float");
+ root->resetValue("/home/user/QChar");
+ root->resetValue("/home/user");
+ root->resetValue("/home/usercount");
+ root->resetValue("/home");
+ root->resetValue("/layer/name");
+ root->resetValue("/layer/id");
+ root->resetValue("/layer/options");
+ root->resetValue("/layer");
+ }
+
+ delete root;
+ }
+
+ foreach (QAbstractValueSpaceLayer *layer, busys.keys()) {
+ QValueSpacePublisher *busy = busys.take(layer);
+
+ if (layer->layerOptions() & QValueSpace::PermanentLayer) {
+ busy->resetValue("alex/busy");
+ busy->resetValue("alex");
+ busy->resetValue("lorn/busy");
+ busy->resetValue("lorn");
+ busy->resetValue(QString());
+ }
+
+ delete busy;
+ }
+}
+
+void tst_QValueSpaceSubscriber::dataVersatility_data()
+{
+ QTest::addColumn<QAbstractValueSpaceLayer *>("layer");
+
+ QTest::addColumn< QVariant >("data");
+ QTest::addColumn< QString >("typeString");
+ QTest::addColumn< int >("typeIdent");
+
+ QList<QAbstractValueSpaceLayer *> layers = QValueSpaceManager::instance()->getLayers();
+ for (int i = 0; i < layers.count(); ++i) {
+ QAbstractValueSpaceLayer *layer = layers.at(i);
+
+ //these types have custom loading/saving operator
+ QTest::newRow("Int") << layer
+ << QVariant((int)567) << "Int" << (int)QVariant::Int;
+ QTest::newRow("Bool") << layer
+ << QVariant((bool)true) << "Bool" << (int)QVariant::Bool;
+ QTest::newRow("UInt") << layer
+ << QVariant((unsigned int)4) << "UInt" << (int)QVariant::UInt;
+ QTest::newRow("LongLong") << layer
+ << QVariant((long long)5) << "LongLong" << (int)QVariant::LongLong;
+ QTest::newRow("ULongLong") << layer
+ << QVariant((unsigned long long)6) << "ULongLong" << (int)QVariant::ULongLong;
+ QTest::newRow("Double") << layer
+ << QVariant((double)4.5) << "Double" << (int)QVariant::Double;
+ QTest::newRow("QChar") << layer
+ << QVariant(QChar('@')) << "Char" << (int)QVariant::Char;
+ QTest::newRow("QString") << layer
+ << QVariant(QString("asd")) << "QString" << (int)QVariant::String;
+ QTest::newRow("QByteArray") << layer
+ << QVariant(QByteArray("bytearray")) << "QByteArray" << (int)QVariant::ByteArray;
+ QTest::newRow("QStringList") << layer
+ << QVariant(QStringList() << QString("String 1") << QString("String 2"))
+ << "QStringList" << (int)QVariant::StringList;
+
+ //other types not specifically covered by valuespace -> uses QVariant based serialization
+ QTest::newRow("QRect") << layer
+ << QVariant(QRect(4,5,6,7)) << "QRect" << (int)QVariant::Rect;
+ QTest::newRow("QDateTime") << layer
+ << QVariant(QDateTime::currentDateTime()) << "QDateTime" << (int)QVariant::DateTime;
+ }
+}
+
+void tst_QValueSpaceSubscriber::dataVersatility()
+{
+ QFETCH(QAbstractValueSpaceLayer *, layer);
+
+ QFETCH(QVariant, data);
+ QFETCH(QString, typeString);
+ QFETCH(int, typeIdent);
+
+ QCOMPARE(data.type(), (QVariant::Type)typeIdent);
+
+ QValueSpacePublisher publisher(layer->id(), "/usr/data");
+ publisher.setValue(typeString, data);
+ publisher.sync();
+ QValueSpaceSubscriber subscriber(layer->id(), "/usr/data");
+ QVariant v = subscriber.value(typeString);
+
+ QCOMPARE(v.type(), (QVariant::Type)typeIdent);
+ QCOMPARE(v, data);
+
+ if (layer->layerOptions() & QValueSpace::PermanentLayer)
+ publisher.resetValue(typeString);
+}
+
+void tst_QValueSpaceSubscriber::testConstructor_data()
+{
+ QTest::addColumn< QVariant >("testItem");
+ QTest::addColumn< QVariant >("value");
+ QTest::addColumn< QStringList >("subPaths");
+ QTest::addColumn< QString >("path");
+ QTest::addColumn< QString >("relItemPath");
+ QTest::addColumn< int >("expectedValue");
+
+ QStringList allPaths;
+ allPaths << "bool" << "int" << "QString" << "QStringList" << "qint64" << "QByteArray"
+ << "double" << "float" << "QChar";
+
+ QStringList rootPaths;
+ rootPaths << "home" << "usr" << "layer";
+
+ QStringList homePaths;
+ homePaths << "user" << "usercount";
+
+ QVariant data;
+ QValueSpaceSubscriber *subscriber;
+
+ // Subscribers with / path.
+ subscriber = new QValueSpaceSubscriber(QString(), this);
+ qVariantSetValue(data, subscriber);
+ QTest::newRow("QValueSpaceSubscriber(QString(), this)")
+ << data
+ << QVariant()
+ << rootPaths
+ << QString("/")
+ << QString("home/user/int")
+ << 3;
+
+ subscriber = new QValueSpaceSubscriber(QString("/"), this);
+ qVariantSetValue(data, subscriber);
+ QTest::newRow("QValueSpaceSubscriber(QString(\"/\"), this)")
+ << data
+ << QVariant()
+ << rootPaths
+ << QString("/")
+ << QString("home/user/int")
+ << 3;
+
+ subscriber = new QValueSpaceSubscriber("", this);
+ qVariantSetValue(data, subscriber);
+ QTest::newRow("QValueSpaceSubscriber(\"\", this)")
+ << data
+ << QVariant()
+ << rootPaths
+ << QString("/")
+ << QString("home/user/int")
+ << 3;
+
+ subscriber = new QValueSpaceSubscriber("/", this);
+ qVariantSetValue(data, subscriber);
+ QTest::newRow("QValueSpaceSubscriber(\"/\", this)")
+ << data
+ << QVariant()
+ << rootPaths
+ << QString("/")
+ << QString("home/user/int")
+ << 3;
+
+ subscriber = new QValueSpaceSubscriber(this);
+ qVariantSetValue(data, subscriber);
+ QTest::newRow("QValueSpaceSubscriber(this)")
+ << data
+ << QVariant()
+ << rootPaths
+ << QString("/")
+ << QString("home/user/int")
+ << 3;
+
+ // Subscribers with /home path.
+ subscriber = new QValueSpaceSubscriber(QString("/home"), this);
+ qVariantSetValue(data, subscriber);
+ QTest::newRow("QValueSpaceSubscriber(QString(\"/home\"), this)")
+ << data
+ << QVariant()
+ << homePaths
+ << QString("/home")
+ << QString("user/int")
+ << 3;
+
+ // Subscribers with /home/user path.
+ subscriber = new QValueSpaceSubscriber(QString("/home/user"), this);
+ qVariantSetValue(data, subscriber);
+ QTest::newRow("QValueSpaceSubscriber(QString(\"/home/user\"), this)")
+ << data
+ << QVariant()
+ << allPaths
+ << QString("/home/user")
+ << QString("int")
+ << 3;
+
+ // Direct value subscriber with /home/user/int path.
+ subscriber = new QValueSpaceSubscriber("/home/user/int", this);
+ qVariantSetValue(data, subscriber);
+ QTest::newRow("QValueSpaceSubscriber(\"/home/user/int\", this)")
+ << data
+ << QVariant(3)
+ << QStringList()
+ << QString("/home/user/int")
+ << QString()
+ << 3;
+
+ // Subscriber with invalid path.
+ subscriber = new QValueSpaceSubscriber(QString("/home/invalidPath"), this);
+ qVariantSetValue(data, subscriber);
+ QTest::newRow("QValueSpaceSubscriber(QString(\"/home/invalidPath\"), this)")
+ << data
+ << QVariant()
+ << QStringList()
+ << QString("/home/invalidPath")
+ << QString("user/int")
+ << 100; //should fails -> returns default
+
+ // setPath to /
+ subscriber = new QValueSpaceSubscriber(this);
+ subscriber->setPath("/");
+ qVariantSetValue(data, subscriber);
+ QTest::newRow("QValueSpaceSubscriber::setPath(\"/\"")
+ << data
+ << QVariant()
+ << rootPaths
+ << QString("/")
+ << QString("home/user/int")
+ << 3;
+
+ // setPath to /home
+ subscriber = new QValueSpaceSubscriber(this);
+ subscriber->setPath("/home");
+ qVariantSetValue(data, subscriber);
+ QTest::newRow("QValueSpaceSubscriber::setPath(\"/home\")")
+ << data
+ << QVariant()
+ << homePaths
+ << QString("/home")
+ << QString("user/int")
+ << 3;
+
+ // setPath to /home/user
+ subscriber = new QValueSpaceSubscriber(this);
+ subscriber->setPath("/home/user");
+ qVariantSetValue(data, subscriber);
+ QTest::newRow("QValueSpaceSubscriber::setPath(\"/home/user\")")
+ << data
+ << QVariant()
+ << allPaths
+ << QString("/home/user")
+ << QString("int")
+ << 3;
+
+ // setPath to &QValueSpaceSubscriber
+ subscriber = new QValueSpaceSubscriber(this);
+ {
+ QValueSpaceSubscriber user("/home/user");
+ subscriber->setPath(&user);
+ }
+ qVariantSetValue(data, subscriber);
+ QTest::newRow("QValueSpaceSubscriber::setPath(&QValueSpaceSubscriber(\"/home/user\")")
+ << data
+ << QVariant()
+ << allPaths
+ << QString("/home/user")
+ << QString("int")
+ << 3;
+}
+
+void tst_QValueSpaceSubscriber::testConstructor()
+{
+ QFETCH(QVariant, testItem);
+ QFETCH(QVariant, value);
+ QFETCH(QStringList, subPaths);
+ QFETCH(QString, path);
+ QFETCH(QString, relItemPath);
+ QFETCH(int, expectedValue);
+
+ QValueSpaceSubscriber *subscriber = qvariant_cast<QValueSpaceSubscriber*>(testItem);
+ QCOMPARE(subscriber->parent(), (QObject*)this);
+ QCOMPARE(subscriber->value(), value);
+ QVERIFY(subscriber->subPaths().toSet().contains(subPaths.toSet()));
+ QCOMPARE(subscriber->path(), path);
+ QCOMPARE(subscriber->value(relItemPath, 100).toInt(), expectedValue);
+}
+
+#define ADD(opt, invalid) do {\
+ QTest::newRow(QString::number(opt).append(" const QString &").toLocal8Bit().constData()) \
+ << (QValueSpace::UnspecifiedLayer | opt) << invalid; \
+} while (false)
+
+void tst_QValueSpaceSubscriber::testFilterConstructor_data()
+{
+ QTest::addColumn<QValueSpace::LayerOptions>("options");
+ QTest::addColumn<bool>("connected");
+
+ QList<QAbstractValueSpaceLayer *> layers = QValueSpaceManager::instance()->getLayers();
+
+ for (int i = 0; i < layers.count(); ++i) {
+ QAbstractValueSpaceLayer *layer = layers.at(i);
+
+ ADD(layer->layerOptions(), true);
+ }
+
+ ADD(QValueSpace::UnspecifiedLayer, true);
+ ADD(QValueSpace::PermanentLayer, true);
+ ADD(QValueSpace::TransientLayer, true);
+ ADD(QValueSpace::PermanentLayer | QValueSpace::TransientLayer, false);
+ ADD(QValueSpace::WritableLayer, true);
+ ADD(QValueSpace::ReadOnlyLayer, true);
+ ADD(QValueSpace::WritableLayer | QValueSpace::ReadOnlyLayer, false);
+}
+
+void tst_QValueSpaceSubscriber::testFilterConstructor()
+{
+ QFETCH(QValueSpace::LayerOptions, options);
+ QFETCH(bool, connected);
+
+ QValueSpaceSubscriber *subscriber;
+
+ subscriber = new QValueSpaceSubscriber(options, QString("/layer"));
+
+ if (!connected)
+ QVERIFY(!subscriber->isConnected());
+
+ if (subscriber->isConnected()) {
+ QValueSpace::LayerOptions actualOptions =
+ QValueSpace::LayerOptions(subscriber->value("options", 0).toUInt());
+
+ QVERIFY(options == QValueSpace::UnspecifiedLayer || actualOptions & options);
+ }
+}
+
+void tst_QValueSpaceSubscriber::testPathChanges()
+{
+ QValueSpaceSubscriber subscriber;
+
+ QStringList rootPaths;
+ rootPaths << "layer" << "usr" << "home";
+
+ QStringList homePaths;
+ homePaths << "user" << "usercount";
+
+ QStringList homeUserPaths;
+ homeUserPaths << "bool" << "int" << "QString" << "QStringList" << "qint64" << "QByteArray"
+ << "double" << "float" << "QChar";
+
+ QCOMPARE(subscriber.path(), QLatin1String("/"));
+ QVERIFY(subscriber.subPaths().toSet().contains(rootPaths.toSet()));
+
+ subscriber.cd("home");
+ QCOMPARE(subscriber.path(), QLatin1String("/home"));
+ QVERIFY(subscriber.subPaths().toSet().contains(homePaths.toSet()));
+
+ subscriber.cd("user");
+ QCOMPARE(subscriber.path(), QLatin1String("/home/user"));
+ QVERIFY(subscriber.subPaths().toSet().contains(homeUserPaths.toSet()));
+
+ subscriber.cdUp();
+ QCOMPARE(subscriber.path(), QLatin1String("/home"));
+ QVERIFY(subscriber.subPaths().toSet().contains(homePaths.toSet()));
+
+ subscriber.cd("/home/user");
+ QCOMPARE(subscriber.path(), QLatin1String("/home/user"));
+ QVERIFY(subscriber.subPaths().toSet().contains(homeUserPaths.toSet()));
+}
+
+void tst_QValueSpaceSubscriber::contentsChanged_data()
+{
+ QTest::addColumn<QAbstractValueSpaceLayer *>("layer");
+
+ QTest::addColumn<bool>("implicit");
+ QTest::addColumn< QString >("subscriber_path");
+ QTest::addColumn< QString >("value_path");
+ QTest::addColumn< int >("should_emit_signal");
+ QTest::addColumn< bool >("old_value");
+ QTest::addColumn< bool >("new_value");
+
+ QList<QAbstractValueSpaceLayer *> layers = QValueSpaceManager::instance()->getLayers();
+ for (int i = 0; i < layers.count(); ++i) {
+ QAbstractValueSpaceLayer *layer = layers.at(i);
+
+ QTest::newRow(layer->name().append(": implicit (empty)").toLocal8Bit().constData())
+ << layer
+ << true
+ << ""
+ << "usr/alex/busy"
+ << 1
+ << false
+ << true;
+
+ QTest::newRow(layer->name().append(": explicit (empty)").toLocal8Bit().constData())
+ << layer
+ << false
+ << ""
+ << "usr/alex/busy"
+ << 1
+ << false
+ << true;
+
+ QTest::newRow(layer->name().append(": implicit /").toLocal8Bit().constData())
+ << layer
+ << true
+ << "/"
+ << "usr/alex/busy"
+ << 1
+ << false
+ << true;
+
+ QTest::newRow(layer->name().append(": explicit /").toLocal8Bit().constData())
+ << layer
+ << false
+ << "/"
+ << "usr/alex/busy"
+ << 1
+ << false
+ << true;
+
+ QTest::newRow(layer->name().append(": implicit /usr").toLocal8Bit().constData())
+ << layer
+ << true
+ << "/usr"
+ << "alex/busy"
+ << 1
+ << false
+ << true;
+
+ QTest::newRow(layer->name().append(": explicit /usr").toLocal8Bit().constData())
+ << layer
+ << false
+ << "/usr"
+ << "alex/busy"
+ << 1
+ << false
+ << true;
+
+ QTest::newRow(layer->name().append(": implicit /usr/alex").toLocal8Bit().constData())
+ << layer
+ << true
+ << "/usr/alex"
+ << "busy"
+ << 1
+ << false
+ << true;
+
+ QTest::newRow(layer->name().append(": explicit /usr/alex").toLocal8Bit().constData())
+ << layer
+ << false
+ << "/usr/alex"
+ << "busy"
+ << 1
+ << false
+ << true;
+
+ QTest::newRow(layer->name().append(": implicit /usr/alex/busy").toLocal8Bit().constData())
+ << layer
+ << true
+ << "/usr/alex/busy"
+ << ""
+ << 1
+ << false
+ << true;
+
+ QTest::newRow(layer->name().append(": explicit /usr/alex/busy").toLocal8Bit().constData())
+ << layer
+ << false
+ << "/usr/alex/busy"
+ << ""
+ << 1
+ << false
+ << true;
+
+ QTest::newRow(layer->name().append(": implicit /usr/lorn").toLocal8Bit().constData())
+ << layer
+ << true
+ << "/usr/lorn"
+ << "busy"
+ << 0
+ << false
+ << false;
+
+ QTest::newRow(layer->name().append(": explicit /usr/lorn").toLocal8Bit().constData())
+ << layer
+ << false
+ << "/usr/lorn"
+ << "busy"
+ << 0
+ << false
+ << false;
+ }
+}
+
+void tst_QValueSpaceSubscriber::contentsChanged()
+{
+ QFETCH(QAbstractValueSpaceLayer *, layer);
+
+ QFETCH(bool, implicit);
+ QFETCH(QString, subscriber_path);
+ QFETCH(QString, value_path);
+ QFETCH(int, should_emit_signal);
+ QFETCH(bool, old_value);
+ QFETCH(bool, new_value);
+
+ QValueSpacePublisher *busy = busys.value(layer);
+
+ busy->setValue("alex/busy", old_value);
+ busy->sync();
+
+ QValueSpaceSubscriber subscriber(layer->id(), subscriber_path);
+ QCOMPARE(subscriber.value(value_path,!old_value).toBool(), old_value);
+
+ ChangeListener* listener = 0;
+ QSignalSpy *spy;
+ if (implicit) {
+ listener = new ChangeListener;
+ spy = new QSignalSpy(listener, SIGNAL(baseChanged()));
+ connect(&subscriber, SIGNAL(contentsChanged()), listener, SIGNAL(baseChanged()));
+ } else {
+ spy = new QSignalSpy(&subscriber, SIGNAL(contentsChanged()));
+ subscriber.property("value");
+ }
+
+ #ifdef Q_OS_LINUX
+ //Wait for possible asynchronously emitted signals
+ QEventLoop loop;
+ QTimer::singleShot(100, &loop, SLOT(quit()));
+ loop.exec();
+ spy->clear();
+ #endif
+
+ QCOMPARE(spy->count(), 0);
+
+ busy->setValue("alex/busy", new_value);
+ busy->sync();
+
+ QTRY_COMPARE(spy->count(), should_emit_signal);
+ QCOMPARE(subscriber.value(value_path,!old_value).toBool(), new_value);
+
+ spy->clear();
+
+ //removing the value triggers signal
+ busy->resetValue("alex/busy");
+ busy->sync();
+ QTRY_COMPARE(spy->count(), should_emit_signal);
+ QCOMPARE(subscriber.value(value_path,!old_value).toBool(), new_value);
+
+ spy->clear();
+ busy->setValue("alex/busy", new_value);
+ busy->sync();
+
+ QTRY_COMPARE(spy->count(), should_emit_signal);
+ QCOMPARE(subscriber.value(value_path,!old_value).toBool(), new_value);
+
+ if (listener)
+ disconnect(&subscriber, SIGNAL(contentsChanged()), listener, SIGNAL(baseChanged()));
+
+ delete spy;
+ delete listener;
+}
+
+void tst_QValueSpaceSubscriber::value_data()
+{
+ QTest::addColumn<QAbstractValueSpaceLayer *>("layer");
+
+ QList<QAbstractValueSpaceLayer *> layers = QValueSpaceManager::instance()->getLayers();
+ for (int i = 0; i < layers.count(); ++i)
+ QTest::newRow(layers.at(i)->name().toLocal8Bit().constData()) << layers.at(i);
+}
+
+void tst_QValueSpaceSubscriber::value()
+{
+ QFETCH(QAbstractValueSpaceLayer *, layer);
+
+ QValueSpaceSubscriber base(layer->id(), QString("/"));
+ QCOMPARE(base.value("home/usercount", 5).toInt(), 1);
+ QCOMPARE(base.value("home/user/QString", "default").toString(), QString("testString"));
+ QCOMPARE(base.value("home/user/bool", false).toBool(), true);
+ QCOMPARE(base.value("home/user/int", 5).toInt(), 3);
+ QCOMPARE(base.value("home/user/QByteArray", QByteArray("invalid")).toByteArray(),
+ QByteArray("testByteArray"));
+ QVERIFY(fabs(base.value("home/user/double", 4.0).toDouble() - double(4.56)) < 0.01);
+ //QCOMPARE(base.value("home/user/float", 4.0).toDouble(), (double)4.56);
+
+ QValueSpaceSubscriber base1(layer->id(), QString("/home"));
+ QCOMPARE(base1.value(QString("usercount"), 5).toInt(), 1);
+ QCOMPARE(base1.value(QString("user/QString"), "default").toString(), QString("testString"));
+ QCOMPARE(base1.value("user/bool", false).toBool(), true);
+ QCOMPARE(base1.value("user/int", 5).toInt(), 3);
+ QCOMPARE(base1.value("user/QByteArray", QByteArray("invalid")).toByteArray(),
+ QByteArray("testByteArray"));
+ QVERIFY(fabs(base.value("home/user/double", 4.0).toDouble() - double(4.56)) < 0.01);
+ //QCOMPARE(base1.value("user/float", 4.0).toDouble(), double(4.56));
+
+ QValueSpaceSubscriber base2(layer->id(), QString("/home/user"));
+ QCOMPARE(base2.value(QString("usercount"), 5).toInt(), 5);
+ QCOMPARE(base2.value(QString("QString"), "default").toString(), QString("testString"));
+ QCOMPARE(base2.value("bool", false).toBool(), true);
+ QCOMPARE(base2.value("int", 5).toInt(), 3);
+ QCOMPARE(base2.value("QByteArray", QByteArray("invalid")).toByteArray(),
+ QByteArray("testByteArray"));
+ QVERIFY(fabs(base.value("home/user/double", 4.0).toDouble() - double(4.56)) < 0.01);
+ //QCOMPARE(base2.value("float", 4.0).toDouble(), 4.56);
+}
+
+void tst_QValueSpaceSubscriber::ipcTests_data()
+{
+#ifdef QT_NO_PROCESS
+ QSKIP("Qt was compiled with QT_NO_PROCESS", SkipAll);
+#else
+ QTest::addColumn<QAbstractValueSpaceLayer *>("layer");
+
+ QList<QAbstractValueSpaceLayer *> layers = QValueSpaceManager::instance()->getLayers();
+ for (int i = 0; i < layers.count(); ++i)
+ QTest::newRow(layers.at(i)->name().toLocal8Bit().constData()) << layers.at(i);
+#endif
+}
+
+void tst_QValueSpaceSubscriber::ipcTests()
+{
+#ifdef Q_OS_SYMBIAN
+ QSKIP("No multiple processes in Symbian emulator", SkipAll);
+#endif
+
+#if defined(QT_NO_PROCESS)
+ QSKIP("Qt was compiled with QT_NO_PROCESS", SkipAll);
+#else
+ QFETCH(QAbstractValueSpaceLayer *, layer);
+
+ QValueSpaceSubscriber subscriber(layer->id(), "/usr/lackey/subdir/value");
+ ChangeListener listener;
+ QSignalSpy spy(&listener, SIGNAL(baseChanged()));
+ connect(&subscriber, SIGNAL(contentsChanged()), &listener, SIGNAL(baseChanged()));
+
+ QProcess process;
+ process.setProcessChannelMode(QProcess::ForwardedChannels);
+#ifdef Q_OS_UNIX
+ process.start("./vsiTestLackey", QStringList() << "-ipcTests" << layer->id().toString());
+#else
+ process.start("vsiTestLackey", QStringList() << "-ipcTests" << layer->id().toString());
+#endif
+ QVERIFY(process.waitForStarted());
+
+ //lackey sets value to 100 as part of its startup
+ QTRY_COMPARE(spy.count(), 1);
+ QCOMPARE(subscriber.value("", 99).toInt(), 100);
+ spy.clear();
+
+ //lackey sets value to 101
+ QTRY_COMPARE(spy.count(), 1);
+ QCOMPARE(subscriber.value("", 99).toInt(), 101);
+ spy.clear();
+
+ //value was removed -> returns default
+ QTRY_COMPARE(spy.count(), 1);
+ QCOMPARE(subscriber.value("", 99).toInt(), 99);
+ spy.clear();
+
+ //lackey sets value to 102
+ QTRY_COMPARE(spy.count(), 1);
+ QCOMPARE(subscriber.value("", 99).toInt(), 102);
+ spy.clear();
+
+ //value was removed -> returns default
+ QTRY_COMPARE(spy.count(), 1);
+ QCOMPARE(subscriber.value("", 99).toInt(), 99);
+
+ QVERIFY(process.waitForFinished(10000));
+#endif
+}
+
+void tst_QValueSpaceSubscriber::ipcRemoveKey_data()
+{
+#ifdef QT_NO_PROCESS
+ QSKIP("Qt was compiled with QT_NO_PROCESS", SkipAll);
+#else
+ QTest::addColumn<QAbstractValueSpaceLayer *>("layer");
+
+ bool skip = true;
+
+ QList<QAbstractValueSpaceLayer *> layers = QValueSpaceManager::instance()->getLayers();
+ for (int i = 0; i < layers.count(); ++i) {
+ QAbstractValueSpaceLayer *layer = layers.at(i);
+
+ if (layer->layerOptions() & QValueSpace::PermanentLayer)
+ continue;
+
+ skip = false;
+
+ QTest::newRow(layer->name().toLocal8Bit().constData()) << layer;
+ }
+
+ if (skip)
+ QSKIP("No applicable layers found.", SkipAll);
+#endif
+}
+
+void tst_QValueSpaceSubscriber::ipcRemoveKey()
+{
+#if defined(QT_NO_PROCESS)
+ QSKIP("Qt was compiled with QT_NO_PROCESS", SkipAll);
+#else
+ QFETCH(QAbstractValueSpaceLayer *, layer);
+
+ QValueSpaceSubscriber subscriber(layer->id(), "/ipcRemoveKey");
+
+ ChangeListener listener;
+ QSignalSpy changeSpy(&listener, SIGNAL(baseChanged()));
+ QObject::connect(&subscriber, SIGNAL(contentsChanged()), &listener, SIGNAL(baseChanged()));
+
+ QProcess process;
+ process.setProcessChannelMode(QProcess::ForwardedChannels);
+#ifdef Q_OS_UNIX
+ process.start("./vsiTestLackey", QStringList() << "-ipcRemoveKey" << layer->id().toString());
+#else
+ process.start("vsiTestLackey", QStringList() << "-ipcRemoveKey" << layer->id().toString());
+#endif
+ QVERIFY(process.waitForStarted());
+
+ // Wait for lackey to create "value".
+ QTRY_COMPARE(changeSpy.count(), 1);
+ QCOMPARE(subscriber.value("value", 5).toInt(), 100);
+
+ // Wait for lackey to delete key "/ipcRemoveKey".
+ changeSpy.clear();
+ QTRY_COMPARE(changeSpy.count(), 1);
+
+ QVERIFY(subscriber.subPaths().isEmpty());
+ QCOMPARE(subscriber.value("value", 6).toInt(), 6);
+ QVERIFY(process.waitForFinished(10000));
+#endif
+}
+
+void tst_QValueSpaceSubscriber::interestNotification_data()
+{
+ QTest::addColumn<QAbstractValueSpaceLayer *>("layer");
+
+ QTest::addColumn<QString>("publisherPath");
+ QTest::addColumn<QString>("attribute");
+
+ bool foundSupported = false;
+
+ QList<QAbstractValueSpaceLayer *> layers = QValueSpaceManager::instance()->getLayers();
+ for (int i = 0; i < layers.count(); ++i) {
+ QAbstractValueSpaceLayer *layer = layers.at(i);
+
+ if (!layer->supportsInterestNotification())
+ continue;
+
+ foundSupported = true;
+
+ QTest::newRow("QValueSpaceSubscriber(QString)")
+ << layer << "/interestNotification" << "/value";
+ }
+
+ if (!foundSupported)
+ QSKIP("No layer supporting interest notifications found.", SkipAll);
+}
+
+void tst_QValueSpaceSubscriber::interestNotification()
+{
+ QFETCH(QAbstractValueSpaceLayer *, layer);
+
+ QFETCH(QString, publisherPath);
+ QFETCH(QString, attribute);
+
+ QValueSpacePublisher *publisher;
+ publisher = new QValueSpacePublisher(layer->id(), publisherPath);
+
+ ChangeListener notificationListener;
+ connect(publisher, SIGNAL(interestChanged(QString,bool)),
+ ¬ificationListener, SIGNAL(interestChanged(QString,bool)));
+
+ QSignalSpy notificationSpy(¬ificationListener,
+ SIGNAL(interestChanged(QString,bool)));
+
+ const QString subscriberPath = publisherPath + attribute;
+
+ QValueSpaceSubscriber *subscriber = new QValueSpaceSubscriber(layer->id(), subscriberPath);
+
+ QTRY_COMPARE(notificationSpy.count(), 1);
+
+ QList<QVariant> arguments = notificationSpy.takeFirst();
+ QCOMPARE(arguments.at(0).type(), QVariant::String);
+ QCOMPARE(arguments.at(0).toString(), attribute);
+ QCOMPARE(arguments.at(1).type(), QVariant::Bool);
+ QCOMPARE(arguments.at(1).toBool(), true);
+
+ QCOMPARE(subscriber->value(QString(), 10).toInt(), 10);
+
+ publisher->setValue(attribute, 5);
+ publisher->sync();
+
+ QCOMPARE(subscriber->value(QString(), 10).toInt(), 5);
+
+ notificationSpy.clear();
+
+ delete subscriber;
+
+ QTRY_COMPARE(notificationSpy.count(), 1);
+
+ arguments = notificationSpy.takeFirst();
+ QCOMPARE(arguments.at(0).type(), QVariant::String);
+ QCOMPARE(arguments.at(0).toString(), attribute);
+ QCOMPARE(arguments.at(1).type(), QVariant::Bool);
+ QCOMPARE(arguments.at(1).toBool(), false);
+
+ delete publisher;
+}
+
+void tst_QValueSpaceSubscriber::ipcInterestNotification_data()
+{
+#ifdef QT_NO_PROCESS
+ QSKIP("Qt was compiled with QT_NO_PROCESS", SkipAll);
+#else
+ QTest::addColumn<QAbstractValueSpaceLayer *>("layer");
+
+ bool foundSupported = false;
+
+ QList<QAbstractValueSpaceLayer *> layers = QValueSpaceManager::instance()->getLayers();
+ for (int i = 0; i < layers.count(); ++i) {
+ QAbstractValueSpaceLayer *layer = layers.at(i);
+
+ if (!layer->supportsInterestNotification())
+ continue;
+
+ foundSupported = true;
+
+ QTest::newRow(layer->name().toLocal8Bit().constData()) << layer;
+ }
+
+ if (!foundSupported)
+ QSKIP("No layer supporting interest notifications found.", SkipAll);
+#endif
+}
+
+void tst_QValueSpaceSubscriber::ipcInterestNotification()
+{
+#if defined(QT_NO_PROCESS)
+ QSKIP("Qt was compiled with QT_NO_PROCESS", SkipAll);
+#else
+ QFETCH(QAbstractValueSpaceLayer *, layer);
+
+ // Test QValueSpaceSubscriber construction before QValueSpacePublisher.
+
+ QValueSpaceSubscriber *subscriber =
+ new QValueSpaceSubscriber(layer->id(), "/ipcInterestNotification/value");
+
+ ChangeListener listener;
+ QObject::connect(subscriber, SIGNAL(contentsChanged()), &listener, SIGNAL(baseChanged()));
+ QSignalSpy changeSpy(&listener, SIGNAL(baseChanged()));
+
+ // Lackey is not running, so value will not exist.
+ QCOMPARE(subscriber->value(QString(), 10).toInt(), 10);
+
+ QProcess process;
+ process.setProcessChannelMode(QProcess::ForwardedChannels);
+#ifdef Q_OS_UNIX
+ process.start("./vsiTestLackey", QStringList()
+ << "-ipcInterestNotification" << layer->id().toString());
+#else
+ process.start("vsiTestLackey", QStringList()
+ << "-ipcInterestNotification" << layer->id().toString());
+#endif
+ QVERIFY(process.waitForStarted());
+
+ // Lackey will receive interestChanged from server and set the attribute.
+ QTRY_COMPARE(changeSpy.count(), 1);
+ changeSpy.clear();
+
+ QCOMPARE(subscriber->value(QString(), 10).toInt(), 5);
+
+ // Lackey will receive interestChanged and remove attribute.
+ delete subscriber;
+ QTest::qWait(1000);
+
+ // Test QValueSpaceSubscriber construction after QValueSpacePublisher
+
+ subscriber = new QValueSpaceSubscriber(layer->id(), "/ipcInterestNotification/value");
+ QObject::connect(subscriber, SIGNAL(contentsChanged()), &listener, SIGNAL(baseChanged()));
+
+ QTRY_COMPARE(changeSpy.count(), 1);
+
+ QCOMPARE(subscriber->value(QString(), 10).toInt(), 5);
+#endif
+}
+
+void tst_QValueSpaceSubscriber::clientServer()
+{
+#if defined(QT_START_VALUESPACE)
+ QVERIFY(QValueSpaceManager::instance()->isServer());
+#else
+ QVERIFY(!QValueSpaceManager::instance()->isServer());
+#endif
+}
+
+class WriteThread : public QThread
+{
+ Q_OBJECT
+
+public:
+ WriteThread(const QUuid& layerId);
+
+ void setDone();
+
+protected:
+ void run();
+
+private:
+ QValueSpacePublisher *publisher;
+ bool done;
+ const QUuid& layerId;
+};
+
+WriteThread::WriteThread(const QUuid& layerId)
+: publisher(0), done(false), layerId(layerId)
+{
+}
+
+void WriteThread::setDone()
+{
+ done = true;
+}
+
+void WriteThread::run()
+{
+ QTest::qWait(100); // give some ReadThreads some time to start.
+
+ QValueSpacePublisher publisher(layerId, "/threads");
+
+ uint value = 0;
+ while (!done) {
+ publisher.setValue("value", value);
+ publisher.sync();
+ QTest::qWait(100);
+ value += 100;
+ }
+}
+
+class ReadThread : public QThread
+{
+ Q_OBJECT
+
+public:
+ ReadThread(QValueSpaceSubscriber *subscriber, bool sync, const QUuid& layerId);
+
+protected:
+ void run();
+
+private:
+ QValueSpaceSubscriber *masterSubscriber;
+ int iterations;
+ bool synchronised;
+ const QUuid& layerId;
+};
+
+ReadThread::ReadThread(QValueSpaceSubscriber *subscriber, bool sync, const QUuid& layerId)
+: masterSubscriber(subscriber), iterations(0), synchronised(sync), layerId(layerId)
+{
+}
+
+void ReadThread::run()
+{
+ while (true) {
+ QValueSpaceSubscriber subscriber(layerId, masterSubscriber->path());
+
+ if (synchronised) {
+ QEventLoop loop;
+ connect(&subscriber, SIGNAL(contentsChanged()), &loop, SLOT(quit()));
+ QTimer::singleShot(1000, &loop, SLOT(quit()));
+ loop.exec();
+ }
+
+ ++iterations;
+
+ QVariant value = subscriber.value();
+ if (value.isValid() && value.toUInt() > 1000)
+ break;
+ }
+}
+
+void tst_QValueSpaceSubscriber::threads_data()
+{
+ QTest::addColumn<unsigned int>("threads");
+ QTest::addColumn<bool>("synchronised");
+ QTest::addColumn<QUuid>("layerId");
+
+ QList<QAbstractValueSpaceLayer *> layers = QValueSpaceManager::instance()->getLayers();
+
+ int foundLayers = 0;
+ for (int i = 0; i < layers.count(); ++i) {
+ QAbstractValueSpaceLayer *layer = layers.at(i);
+
+ //GConfLayer can't provide thread-safety because it eventually depends on
+ //DBus which isn't fully thread-safe
+ if (layer->id() == QVALUESPACE_GCONF_LAYER) {
+ continue;
+ }
+
+ const QUuid id = layer->id();
+
+ QTest::newRow("1 thread") << uint(1) << true << id;
+ QTest::newRow("2 threads") << uint(2) << true << id;
+#if defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN)
+ QTest::newRow("10 threads") << uint(10) << true << id;
+#else
+ QTest::newRow("100 threads") << uint(100) << true << id;
+#endif
+ QTest::newRow("1 thread, unsynchronised") << uint(1) << false << id;
+ QTest::newRow("2 threads, unsynchronised") << uint(2) << false << id;
+#if defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN)
+ QTest::newRow("10 threads") << uint(10) << false << id;
+#else
+ QTest::newRow("100 threads, unsynchronised") << uint(100) << false << id;
+#endif
+ foundLayers++;
+ }
+
+ if (foundLayers == 0)
+ QSKIP("No layers providing thread-safety found", SkipAll);
+}
+
+void tst_QValueSpaceSubscriber::threads()
+{
+ QFETCH(unsigned int, threads);
+ QFETCH(bool, synchronised);
+ QFETCH(QUuid, layerId);
+
+ QEventLoop writeLoop;
+ WriteThread *writeThread = new WriteThread(layerId);
+ connect(writeThread, SIGNAL(finished()), &writeLoop, SLOT(quit()));
+ writeThread->start();
+
+ QValueSpaceSubscriber masterSubscriber(layerId, "/threads/value");
+
+ QVector<ReadThread *> readThreads(threads);
+
+ for (unsigned int i = 0; i < threads; ++i) {
+ readThreads[i] = new ReadThread(&masterSubscriber, synchronised, layerId);
+ readThreads[i]->start();
+ }
+
+ for (unsigned int i = 0; i < threads; ++i) {
+ QEventLoop loop;
+ connect(readThreads[i], SIGNAL(finished()), &loop, SLOT(quit()));
+ if (!readThreads[i]->isFinished())
+ loop.exec();
+
+ delete readThreads[i];
+ }
+
+ writeThread->setDone();
+
+ if (!writeThread->isFinished())
+ writeLoop.exec();
+
+ delete writeThread;
+#ifdef Q_OS_SYMBIAN
+ QValueSpacePublisher resetPublisher(layerId, "/threads");
+ resetPublisher.resetValue("value");
+#endif
+
+}
+
+#include "tst_qvaluespacesubscribershared.moc"