tests/auto/qvaluespacesubscriber/tst_qvaluespacesubscribershared.cpp
changeset 0 876b1a06bc25
child 5 603d3f8b6302
equal deleted inserted replaced
-1:000000000000 0:876b1a06bc25
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the Qt Mobility Components.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "tst_qvaluespacesubscribershared.h"
       
    43 
       
    44 #include <qvaluespacesubscriber.h>
       
    45 #include <qvaluespacepublisher.h>
       
    46 #include <qvaluespacemanager_p.h>
       
    47 
       
    48 #include <QTest>
       
    49 #include <QSet>
       
    50 #include <QSignalSpy>
       
    51 #include <QProcess>
       
    52 #include <QFile>
       
    53 #include <QThread>
       
    54 #include <QTimer>
       
    55 #include <math.h>
       
    56 
       
    57 #include <QDebug>
       
    58 
       
    59 #ifdef Q_OS_WIN
       
    60 #define _WIN32_WINNT 0x0500
       
    61 #include <windows.h>
       
    62 #endif
       
    63 
       
    64 #define ERROR_SETVALUE_NOT_SUPPORTED 1
       
    65 
       
    66 #if defined(Q_OS_SYMBIAN)// || defined (Q_OS_LINUX)
       
    67     #define QTRY_COMPARE(a,e)                       \
       
    68         for (int _i = 0; _i < 100; _i++) {          \
       
    69             if ((a) == (e)) break;                  \
       
    70             QTest::qWait(1);                        \
       
    71         }                                           \
       
    72         QCOMPARE(a, e)
       
    73 
       
    74     #define QTRY_VERIFY(a)                          \
       
    75         for (int _i = 0; _i < 100; _i ++) {         \
       
    76             if (a) break;                           \
       
    77             QTest::qWait(1);                        \
       
    78         }                                           \
       
    79         QVERIFY(a)
       
    80 #else
       
    81     #define QTRY_COMPARE(a,e)                       \
       
    82         for (int _i = 0; _i < 10000; _i += 100) {    \
       
    83             if ((a) == (e)) break;                  \
       
    84             QTest::qWait(100);                      \
       
    85         }                                           \
       
    86         QCOMPARE(a, e)
       
    87 
       
    88     #define QTRY_VERIFY(a)                       \
       
    89         for (int _i = 0; _i < 10000; _i += 100) {    \
       
    90             if (a) break;                  \
       
    91             QTest::qWait(100);                      \
       
    92         }                                           \
       
    93         QVERIFY(a)
       
    94 #endif
       
    95 QTM_USE_NAMESPACE
       
    96 class ChangeListener : public QObject
       
    97 {
       
    98     Q_OBJECT
       
    99 
       
   100 Q_SIGNALS:
       
   101     void baseChanged();
       
   102     void interestChanged(const QString&, bool);
       
   103 };
       
   104 
       
   105 Q_DECLARE_METATYPE(QValueSpaceSubscriber*)
       
   106 Q_DECLARE_METATYPE(QAbstractValueSpaceLayer*)
       
   107 Q_DECLARE_METATYPE(QVariant)
       
   108 Q_DECLARE_METATYPE(QValueSpace::LayerOptions)
       
   109 Q_DECLARE_METATYPE(QUuid)
       
   110 
       
   111 void tst_QValueSpaceSubscriber::initTestCase()
       
   112 {
       
   113     qRegisterMetaType<QVariant>("QVariant");
       
   114     qRegisterMetaType<QValueSpace::LayerOptions>("QValueSpace::LayerOptions");
       
   115 
       
   116 #ifdef Q_OS_WIN
       
   117     HKEY key;
       
   118     long result = RegOpenKeyEx(HKEY_CURRENT_USER, L"Software\\Nokia",
       
   119                                0, KEY_ALL_ACCESS, &key);
       
   120     if (result == ERROR_SUCCESS) {
       
   121         result = RegDeleteKey(key, L"QtMobility\\volatileContext");
       
   122         result = RegDeleteKey(key, L"QtMobility\\nonVolatileContext");
       
   123         result = RegDeleteKey(key, L"QtMobility");
       
   124 
       
   125         RegCloseKey(key);
       
   126     }
       
   127 #endif
       
   128 
       
   129 #if defined(Q_OS_UNIX) && defined(QT_START_VALUESPACE)
       
   130     QFile::remove("/tmp/qt-0/valuespace_shmlayer");
       
   131 #endif
       
   132 
       
   133 #if defined(QT_START_VALUESPACE)
       
   134     QValueSpace::initValueSpaceServer();
       
   135 #endif
       
   136 
       
   137     QList<QAbstractValueSpaceLayer *> layers = QValueSpaceManager::instance()->getLayers();
       
   138     for (int i = 0; i < layers.count(); ++i) {
       
   139         QValueSpacePublisher *root = new QValueSpacePublisher(layers.at(i)->id(), "/");
       
   140         root->setValue("/home/user/bool", true);
       
   141         root->setValue("/home/user/int", 3);
       
   142         root->setValue("/home/user/QString", QString("testString"));
       
   143         QStringList stringList;
       
   144         stringList << QString("String 1") << QString("String 2");
       
   145         root->setValue("/home/user/QStringList", stringList);
       
   146         root->setValue("/home/user/qint64", qint64(64));
       
   147         root->setValue("/home/user/QByteArray", QByteArray("testByteArray"));
       
   148         root->setValue("/home/user/double", 4.56);
       
   149         root->setValue("/home/user/float", (float)4.56f);
       
   150         root->setValue("/home/user/QChar", QChar('c'));
       
   151         //so far not a lot of data types are supported
       
   152         //root->setValue("/home/user/QRect", QRect(0,0,5,6));
       
   153 
       
   154         root->setValue("/home/usercount", 1);
       
   155 
       
   156         root->setValue("/layer/name", layers.at(i)->name());
       
   157         root->setValue("/layer/id", layers.at(i)->id().toString());
       
   158         root->setValue("/layer/options", uint(layers.at(i)->layerOptions()));
       
   159 
       
   160         root->sync();
       
   161 
       
   162         roots.insert(layers.at(i), root);
       
   163 
       
   164         QValueSpacePublisher *busy = new QValueSpacePublisher(layers.at(i)->id(), "/usr");
       
   165         busy->setValue("alex/busy", true);
       
   166         busy->setValue("lorn/busy", false);
       
   167         busy->sync();
       
   168 
       
   169         busys.insert(layers.at(i), busy);
       
   170     }
       
   171 }
       
   172 
       
   173 void tst_QValueSpaceSubscriber::cleanupTestCase()
       
   174 {
       
   175     foreach (QAbstractValueSpaceLayer *layer, roots.keys()) {
       
   176         QValueSpacePublisher *root = roots.take(layer);
       
   177 
       
   178         if (layer->layerOptions() & QValueSpace::PermanentLayer) {
       
   179             root->resetValue("/home/user/bool");
       
   180             root->resetValue("/home/user/int");
       
   181             root->resetValue("/home/user/QString");
       
   182             root->resetValue("/home/user/QStringList");
       
   183             root->resetValue("/home/user/qint64");
       
   184             root->resetValue("/home/user/QByteArray");
       
   185             root->resetValue("/home/user/double");
       
   186             root->resetValue("/home/user/float");
       
   187             root->resetValue("/home/user/QChar");
       
   188             root->resetValue("/home/user");
       
   189             root->resetValue("/home/usercount");
       
   190             root->resetValue("/home");
       
   191             root->resetValue("/layer/name");
       
   192             root->resetValue("/layer/id");
       
   193             root->resetValue("/layer/options");
       
   194             root->resetValue("/layer");
       
   195         }
       
   196 
       
   197         delete root;
       
   198     }
       
   199 
       
   200     foreach (QAbstractValueSpaceLayer *layer, busys.keys()) {
       
   201         QValueSpacePublisher *busy = busys.take(layer);
       
   202 
       
   203         if (layer->layerOptions() & QValueSpace::PermanentLayer) {
       
   204             busy->resetValue("alex/busy");
       
   205             busy->resetValue("alex");
       
   206             busy->resetValue("lorn/busy");
       
   207             busy->resetValue("lorn");
       
   208             busy->resetValue(QString());
       
   209         }
       
   210 
       
   211         delete busy;
       
   212     }
       
   213 }
       
   214 
       
   215 void tst_QValueSpaceSubscriber::dataVersatility_data()
       
   216 {
       
   217     QTest::addColumn<QAbstractValueSpaceLayer *>("layer");
       
   218 
       
   219     QTest::addColumn< QVariant >("data");
       
   220     QTest::addColumn< QString >("typeString");
       
   221     QTest::addColumn< int >("typeIdent");
       
   222 
       
   223     QList<QAbstractValueSpaceLayer *> layers = QValueSpaceManager::instance()->getLayers();
       
   224     for (int i = 0; i < layers.count(); ++i) {
       
   225         QAbstractValueSpaceLayer *layer = layers.at(i);
       
   226 
       
   227         //these types have custom loading/saving operator
       
   228         QTest::newRow("Int") << layer
       
   229             << QVariant((int)567) << "Int" << (int)QVariant::Int;
       
   230         QTest::newRow("Bool") << layer
       
   231             << QVariant((bool)true) << "Bool" << (int)QVariant::Bool;
       
   232         QTest::newRow("UInt") << layer
       
   233             << QVariant((unsigned int)4) << "UInt" << (int)QVariant::UInt;
       
   234         QTest::newRow("LongLong") << layer
       
   235             << QVariant((long long)5) << "LongLong" << (int)QVariant::LongLong;
       
   236         QTest::newRow("ULongLong") << layer
       
   237             << QVariant((unsigned long long)6) << "ULongLong" << (int)QVariant::ULongLong;
       
   238         QTest::newRow("Double") << layer
       
   239             << QVariant((double)4.5) << "Double" << (int)QVariant::Double;
       
   240         QTest::newRow("QChar") << layer
       
   241             << QVariant(QChar('@')) << "Char" << (int)QVariant::Char;
       
   242         QTest::newRow("QString") << layer
       
   243             << QVariant(QString("asd")) << "QString" << (int)QVariant::String;
       
   244         QTest::newRow("QByteArray") << layer
       
   245             << QVariant(QByteArray("bytearray")) << "QByteArray" << (int)QVariant::ByteArray;
       
   246         QTest::newRow("QStringList") << layer
       
   247             << QVariant(QStringList() << QString("String 1") << QString("String 2"))
       
   248             << "QStringList" << (int)QVariant::StringList;
       
   249 
       
   250         //other types not specifically covered by valuespace -> uses QVariant based serialization
       
   251         QTest::newRow("QRect") << layer
       
   252             << QVariant(QRect(4,5,6,7)) << "QRect" << (int)QVariant::Rect;
       
   253         QTest::newRow("QDateTime") << layer
       
   254             << QVariant(QDateTime::currentDateTime()) << "QDateTime" << (int)QVariant::DateTime;
       
   255     }
       
   256 }
       
   257 
       
   258 void tst_QValueSpaceSubscriber::dataVersatility()
       
   259 {
       
   260     QFETCH(QAbstractValueSpaceLayer *, layer);
       
   261 
       
   262     QFETCH(QVariant, data);
       
   263     QFETCH(QString, typeString);
       
   264     QFETCH(int, typeIdent);
       
   265 
       
   266     QCOMPARE(data.type(), (QVariant::Type)typeIdent);
       
   267 
       
   268     QValueSpacePublisher publisher(layer->id(), "/usr/data");
       
   269     publisher.setValue(typeString, data);
       
   270     publisher.sync();
       
   271     QValueSpaceSubscriber subscriber(layer->id(), "/usr/data");
       
   272     QVariant v = subscriber.value(typeString);
       
   273 
       
   274     QCOMPARE(v.type(), (QVariant::Type)typeIdent);
       
   275     QCOMPARE(v, data);
       
   276 
       
   277     if (layer->layerOptions() & QValueSpace::PermanentLayer)
       
   278         publisher.resetValue(typeString);
       
   279 }
       
   280 
       
   281 void tst_QValueSpaceSubscriber::testConstructor_data()
       
   282 {
       
   283     QTest::addColumn< QVariant >("testItem");
       
   284     QTest::addColumn< QVariant >("value");
       
   285     QTest::addColumn< QStringList >("subPaths");
       
   286     QTest::addColumn< QString >("path");
       
   287     QTest::addColumn< QString >("relItemPath");
       
   288     QTest::addColumn< int >("expectedValue");
       
   289 
       
   290     QStringList allPaths;
       
   291     allPaths << "bool" << "int" << "QString" << "QStringList" << "qint64" << "QByteArray"
       
   292              << "double" << "float" << "QChar";
       
   293 
       
   294     QStringList rootPaths;
       
   295     rootPaths << "home" << "usr" << "layer";
       
   296 
       
   297     QStringList homePaths;
       
   298     homePaths << "user" << "usercount";
       
   299 
       
   300     QVariant data;
       
   301     QValueSpaceSubscriber *subscriber;
       
   302 
       
   303     // Subscribers with / path.
       
   304     subscriber = new QValueSpaceSubscriber(QString(), this);
       
   305     qVariantSetValue(data, subscriber);
       
   306     QTest::newRow("QValueSpaceSubscriber(QString(), this)")
       
   307         << data
       
   308         << QVariant()
       
   309         << rootPaths
       
   310         << QString("/")
       
   311         << QString("home/user/int")
       
   312         << 3;
       
   313 
       
   314     subscriber = new QValueSpaceSubscriber(QString("/"), this);
       
   315     qVariantSetValue(data, subscriber);
       
   316     QTest::newRow("QValueSpaceSubscriber(QString(\"/\"), this)")
       
   317         << data
       
   318         << QVariant()
       
   319         << rootPaths
       
   320         << QString("/")
       
   321         << QString("home/user/int")
       
   322         << 3;
       
   323 
       
   324     subscriber = new QValueSpaceSubscriber("", this);
       
   325     qVariantSetValue(data, subscriber);
       
   326     QTest::newRow("QValueSpaceSubscriber(\"\", this)")
       
   327         << data
       
   328         << QVariant()
       
   329         << rootPaths
       
   330         << QString("/")
       
   331         << QString("home/user/int")
       
   332         << 3;
       
   333 
       
   334     subscriber = new QValueSpaceSubscriber("/", this);
       
   335     qVariantSetValue(data, subscriber);
       
   336     QTest::newRow("QValueSpaceSubscriber(\"/\", this)")
       
   337         << data
       
   338         << QVariant()
       
   339         << rootPaths
       
   340         << QString("/")
       
   341         << QString("home/user/int")
       
   342         << 3;
       
   343 
       
   344     subscriber = new QValueSpaceSubscriber(this);
       
   345     qVariantSetValue(data, subscriber);
       
   346     QTest::newRow("QValueSpaceSubscriber(this)")
       
   347         << data
       
   348         << QVariant()
       
   349         << rootPaths
       
   350         << QString("/")
       
   351         << QString("home/user/int")
       
   352         << 3;
       
   353 
       
   354     // Subscribers with /home path.
       
   355     subscriber = new QValueSpaceSubscriber(QString("/home"), this);
       
   356     qVariantSetValue(data, subscriber);
       
   357     QTest::newRow("QValueSpaceSubscriber(QString(\"/home\"), this)")
       
   358         << data
       
   359         << QVariant()
       
   360         << homePaths
       
   361         << QString("/home")
       
   362         << QString("user/int")
       
   363         << 3;
       
   364 
       
   365     // Subscribers with /home/user path.
       
   366     subscriber = new QValueSpaceSubscriber(QString("/home/user"), this);
       
   367     qVariantSetValue(data, subscriber);
       
   368     QTest::newRow("QValueSpaceSubscriber(QString(\"/home/user\"), this)")
       
   369         << data
       
   370         << QVariant()
       
   371         << allPaths
       
   372         << QString("/home/user")
       
   373         << QString("int")
       
   374         << 3;
       
   375 
       
   376     // Direct value subscriber with /home/user/int path.
       
   377     subscriber = new QValueSpaceSubscriber("/home/user/int", this);
       
   378     qVariantSetValue(data, subscriber);
       
   379     QTest::newRow("QValueSpaceSubscriber(\"/home/user/int\", this)")
       
   380         << data
       
   381         << QVariant(3)
       
   382         << QStringList()
       
   383         << QString("/home/user/int")
       
   384         << QString()
       
   385         << 3;
       
   386 
       
   387     // Subscriber with invalid path.
       
   388     subscriber = new QValueSpaceSubscriber(QString("/home/invalidPath"), this);
       
   389     qVariantSetValue(data, subscriber);
       
   390     QTest::newRow("QValueSpaceSubscriber(QString(\"/home/invalidPath\"), this)")
       
   391         << data
       
   392         << QVariant()
       
   393         << QStringList()
       
   394         << QString("/home/invalidPath")
       
   395         << QString("user/int")
       
   396         << 100; //should fails -> returns default
       
   397 
       
   398     // setPath to /
       
   399     subscriber = new QValueSpaceSubscriber(this);
       
   400     subscriber->setPath("/");
       
   401     qVariantSetValue(data, subscriber);
       
   402     QTest::newRow("QValueSpaceSubscriber::setPath(\"/\"")
       
   403         << data
       
   404         << QVariant()
       
   405         << rootPaths
       
   406         << QString("/")
       
   407         << QString("home/user/int")
       
   408         << 3;
       
   409 
       
   410     // setPath to /home
       
   411     subscriber = new QValueSpaceSubscriber(this);
       
   412     subscriber->setPath("/home");
       
   413     qVariantSetValue(data, subscriber);
       
   414     QTest::newRow("QValueSpaceSubscriber::setPath(\"/home\")")
       
   415         << data
       
   416         << QVariant()
       
   417         << homePaths
       
   418         << QString("/home")
       
   419         << QString("user/int")
       
   420         << 3;
       
   421 
       
   422     // setPath to /home/user
       
   423     subscriber = new QValueSpaceSubscriber(this);
       
   424     subscriber->setPath("/home/user");
       
   425     qVariantSetValue(data, subscriber);
       
   426     QTest::newRow("QValueSpaceSubscriber::setPath(\"/home/user\")")
       
   427         << data
       
   428         << QVariant()
       
   429         << allPaths
       
   430         << QString("/home/user")
       
   431         << QString("int")
       
   432         << 3;
       
   433 
       
   434     // setPath to &QValueSpaceSubscriber
       
   435     subscriber = new QValueSpaceSubscriber(this);
       
   436     {
       
   437         QValueSpaceSubscriber user("/home/user");
       
   438         subscriber->setPath(&user);
       
   439     }
       
   440     qVariantSetValue(data, subscriber);
       
   441     QTest::newRow("QValueSpaceSubscriber::setPath(&QValueSpaceSubscriber(\"/home/user\")")
       
   442         << data
       
   443         << QVariant()
       
   444         << allPaths
       
   445         << QString("/home/user")
       
   446         << QString("int")
       
   447         << 3;
       
   448 }
       
   449 
       
   450 void tst_QValueSpaceSubscriber::testConstructor()
       
   451 {
       
   452     QFETCH(QVariant, testItem);
       
   453     QFETCH(QVariant, value);
       
   454     QFETCH(QStringList, subPaths);
       
   455     QFETCH(QString, path);
       
   456     QFETCH(QString, relItemPath);
       
   457     QFETCH(int, expectedValue);
       
   458 
       
   459     QValueSpaceSubscriber *subscriber = qvariant_cast<QValueSpaceSubscriber*>(testItem);
       
   460     QCOMPARE(subscriber->parent(), (QObject*)this);
       
   461     QCOMPARE(subscriber->value(), value);
       
   462     QVERIFY(subscriber->subPaths().toSet().contains(subPaths.toSet()));
       
   463     QCOMPARE(subscriber->path(), path);
       
   464     QCOMPARE(subscriber->value(relItemPath, 100).toInt(), expectedValue);
       
   465 }
       
   466 
       
   467 #define ADD(opt, invalid) do {\
       
   468     QTest::newRow(QString::number(opt).append(" const QString &").toLocal8Bit().constData()) \
       
   469         << (QValueSpace::UnspecifiedLayer | opt) << invalid; \
       
   470 } while (false)
       
   471 
       
   472 void tst_QValueSpaceSubscriber::testFilterConstructor_data()
       
   473 {
       
   474     QTest::addColumn<QValueSpace::LayerOptions>("options");
       
   475     QTest::addColumn<bool>("connected");
       
   476 
       
   477     QList<QAbstractValueSpaceLayer *> layers = QValueSpaceManager::instance()->getLayers();
       
   478 
       
   479     for (int i = 0; i < layers.count(); ++i) {
       
   480         QAbstractValueSpaceLayer *layer = layers.at(i);
       
   481 
       
   482         ADD(layer->layerOptions(), true);
       
   483     }
       
   484 
       
   485     ADD(QValueSpace::UnspecifiedLayer, true);
       
   486     ADD(QValueSpace::PermanentLayer, true);
       
   487     ADD(QValueSpace::TransientLayer, true);
       
   488     ADD(QValueSpace::PermanentLayer | QValueSpace::TransientLayer, false);
       
   489     ADD(QValueSpace::WritableLayer, true);
       
   490     ADD(QValueSpace::ReadOnlyLayer, true);
       
   491     ADD(QValueSpace::WritableLayer | QValueSpace::ReadOnlyLayer, false);
       
   492 }
       
   493 
       
   494 void tst_QValueSpaceSubscriber::testFilterConstructor()
       
   495 {
       
   496     QFETCH(QValueSpace::LayerOptions, options);
       
   497     QFETCH(bool, connected);
       
   498 
       
   499     QValueSpaceSubscriber *subscriber;
       
   500 
       
   501     subscriber = new QValueSpaceSubscriber(options, QString("/layer"));
       
   502 
       
   503     if (!connected)
       
   504         QVERIFY(!subscriber->isConnected());
       
   505 
       
   506     if (subscriber->isConnected()) {
       
   507         QValueSpace::LayerOptions actualOptions =
       
   508             QValueSpace::LayerOptions(subscriber->value("options", 0).toUInt());
       
   509 
       
   510         QVERIFY(options == QValueSpace::UnspecifiedLayer || actualOptions & options);
       
   511     }
       
   512 }
       
   513 
       
   514 void tst_QValueSpaceSubscriber::testPathChanges()
       
   515 {
       
   516     QValueSpaceSubscriber subscriber;
       
   517 
       
   518     QStringList rootPaths;
       
   519     rootPaths << "layer" << "usr" << "home";
       
   520 
       
   521     QStringList homePaths;
       
   522     homePaths << "user" << "usercount";
       
   523 
       
   524     QStringList homeUserPaths;
       
   525     homeUserPaths << "bool" << "int" << "QString" << "QStringList" << "qint64" << "QByteArray"
       
   526                   << "double" << "float" << "QChar";
       
   527 
       
   528     QCOMPARE(subscriber.path(), QLatin1String("/"));
       
   529     QVERIFY(subscriber.subPaths().toSet().contains(rootPaths.toSet()));
       
   530 
       
   531     subscriber.cd("home");
       
   532     QCOMPARE(subscriber.path(), QLatin1String("/home"));
       
   533     QVERIFY(subscriber.subPaths().toSet().contains(homePaths.toSet()));
       
   534 
       
   535     subscriber.cd("user");
       
   536     QCOMPARE(subscriber.path(), QLatin1String("/home/user"));
       
   537     QVERIFY(subscriber.subPaths().toSet().contains(homeUserPaths.toSet()));
       
   538 
       
   539     subscriber.cdUp();
       
   540     QCOMPARE(subscriber.path(), QLatin1String("/home"));
       
   541     QVERIFY(subscriber.subPaths().toSet().contains(homePaths.toSet()));
       
   542 
       
   543     subscriber.cd("/home/user");
       
   544     QCOMPARE(subscriber.path(), QLatin1String("/home/user"));
       
   545     QVERIFY(subscriber.subPaths().toSet().contains(homeUserPaths.toSet()));
       
   546 }
       
   547 
       
   548 void tst_QValueSpaceSubscriber::contentsChanged_data()
       
   549 {
       
   550     QTest::addColumn<QAbstractValueSpaceLayer *>("layer");
       
   551 
       
   552     QTest::addColumn<bool>("implicit");
       
   553     QTest::addColumn< QString >("subscriber_path");
       
   554     QTest::addColumn< QString >("value_path");
       
   555     QTest::addColumn< int >("should_emit_signal");
       
   556     QTest::addColumn< bool >("old_value");
       
   557     QTest::addColumn< bool >("new_value");
       
   558 
       
   559     QList<QAbstractValueSpaceLayer *> layers = QValueSpaceManager::instance()->getLayers();
       
   560     for (int i = 0; i < layers.count(); ++i) {
       
   561         QAbstractValueSpaceLayer *layer = layers.at(i);
       
   562 
       
   563         QTest::newRow(layer->name().append(": implicit (empty)").toLocal8Bit().constData())
       
   564             << layer
       
   565             << true
       
   566             << ""
       
   567             << "usr/alex/busy"
       
   568             << 1
       
   569             << false
       
   570             << true;
       
   571 
       
   572         QTest::newRow(layer->name().append(": explicit (empty)").toLocal8Bit().constData())
       
   573             << layer
       
   574             << false
       
   575             << ""
       
   576             << "usr/alex/busy"
       
   577             << 1
       
   578             << false
       
   579             << true;
       
   580 
       
   581         QTest::newRow(layer->name().append(": implicit /").toLocal8Bit().constData())
       
   582             << layer
       
   583             << true
       
   584             << "/"
       
   585             << "usr/alex/busy"
       
   586             << 1
       
   587             << false
       
   588             << true;
       
   589 
       
   590         QTest::newRow(layer->name().append(": explicit /").toLocal8Bit().constData())
       
   591             << layer
       
   592             << false
       
   593             << "/"
       
   594             << "usr/alex/busy"
       
   595             << 1
       
   596             << false
       
   597             << true;
       
   598 
       
   599         QTest::newRow(layer->name().append(": implicit /usr").toLocal8Bit().constData())
       
   600             << layer
       
   601             << true
       
   602             << "/usr"
       
   603             << "alex/busy"
       
   604             << 1
       
   605             << false
       
   606             << true;
       
   607 
       
   608         QTest::newRow(layer->name().append(": explicit /usr").toLocal8Bit().constData())
       
   609             << layer
       
   610             << false
       
   611             << "/usr"
       
   612             << "alex/busy"
       
   613             << 1
       
   614             << false
       
   615             << true;
       
   616 
       
   617         QTest::newRow(layer->name().append(": implicit /usr/alex").toLocal8Bit().constData())
       
   618             << layer
       
   619             << true
       
   620             << "/usr/alex"
       
   621             << "busy"
       
   622             << 1
       
   623             << false
       
   624             << true;
       
   625 
       
   626         QTest::newRow(layer->name().append(": explicit /usr/alex").toLocal8Bit().constData())
       
   627             << layer
       
   628             << false
       
   629             << "/usr/alex"
       
   630             << "busy"
       
   631             << 1
       
   632             << false
       
   633             << true;
       
   634 
       
   635         QTest::newRow(layer->name().append(": implicit /usr/alex/busy").toLocal8Bit().constData())
       
   636             << layer
       
   637             << true
       
   638             << "/usr/alex/busy"
       
   639             << ""
       
   640             << 1
       
   641             << false
       
   642             << true;
       
   643 
       
   644         QTest::newRow(layer->name().append(": explicit /usr/alex/busy").toLocal8Bit().constData())
       
   645             << layer
       
   646             << false
       
   647             << "/usr/alex/busy"
       
   648             << ""
       
   649             << 1
       
   650             << false
       
   651             << true;
       
   652 
       
   653         QTest::newRow(layer->name().append(": implicit /usr/lorn").toLocal8Bit().constData())
       
   654             << layer
       
   655             << true
       
   656             << "/usr/lorn"
       
   657             << "busy"
       
   658             << 0
       
   659             << false
       
   660             << false;
       
   661 
       
   662         QTest::newRow(layer->name().append(": explicit /usr/lorn").toLocal8Bit().constData())
       
   663             << layer
       
   664             << false
       
   665             << "/usr/lorn"
       
   666             << "busy"
       
   667             << 0
       
   668             << false
       
   669             << false;
       
   670     }
       
   671 }
       
   672 
       
   673 void tst_QValueSpaceSubscriber::contentsChanged()
       
   674 {
       
   675     QFETCH(QAbstractValueSpaceLayer *, layer);
       
   676 
       
   677     QFETCH(bool, implicit);
       
   678     QFETCH(QString, subscriber_path);
       
   679     QFETCH(QString, value_path);
       
   680     QFETCH(int, should_emit_signal);
       
   681     QFETCH(bool, old_value);
       
   682     QFETCH(bool, new_value);
       
   683 
       
   684     QValueSpacePublisher *busy = busys.value(layer);
       
   685 
       
   686     busy->setValue("alex/busy", old_value);
       
   687     busy->sync();
       
   688 
       
   689     QValueSpaceSubscriber subscriber(layer->id(), subscriber_path);
       
   690     QCOMPARE(subscriber.value(value_path,!old_value).toBool(), old_value);
       
   691 
       
   692     ChangeListener* listener = 0;
       
   693     QSignalSpy *spy;
       
   694     if (implicit) {
       
   695         listener = new ChangeListener;
       
   696         spy = new QSignalSpy(listener, SIGNAL(baseChanged()));
       
   697         connect(&subscriber, SIGNAL(contentsChanged()), listener, SIGNAL(baseChanged()));
       
   698     } else {
       
   699         spy = new QSignalSpy(&subscriber, SIGNAL(contentsChanged()));
       
   700         subscriber.property("value");
       
   701     }
       
   702 
       
   703     #ifdef Q_OS_LINUX
       
   704         //Wait for possible asynchronously emitted signals
       
   705         QEventLoop loop;
       
   706         QTimer::singleShot(100, &loop, SLOT(quit()));
       
   707         loop.exec();
       
   708         spy->clear();
       
   709     #endif
       
   710 
       
   711     QCOMPARE(spy->count(), 0);
       
   712 
       
   713     busy->setValue("alex/busy", new_value);
       
   714     busy->sync();
       
   715 
       
   716     QTRY_COMPARE(spy->count(), should_emit_signal);
       
   717     QCOMPARE(subscriber.value(value_path,!old_value).toBool(), new_value);
       
   718 
       
   719     spy->clear();
       
   720 
       
   721     //removing the value triggers signal
       
   722     busy->resetValue("alex/busy");
       
   723     busy->sync();
       
   724     QTRY_COMPARE(spy->count(), should_emit_signal);
       
   725     QCOMPARE(subscriber.value(value_path,!old_value).toBool(), new_value);
       
   726 
       
   727     spy->clear();
       
   728     busy->setValue("alex/busy", new_value);
       
   729     busy->sync();
       
   730 
       
   731     QTRY_COMPARE(spy->count(), should_emit_signal);
       
   732     QCOMPARE(subscriber.value(value_path,!old_value).toBool(), new_value);
       
   733 
       
   734     if (listener)
       
   735         disconnect(&subscriber, SIGNAL(contentsChanged()), listener, SIGNAL(baseChanged()));
       
   736 
       
   737     delete spy;
       
   738     delete listener;
       
   739 }
       
   740 
       
   741 void tst_QValueSpaceSubscriber::value_data()
       
   742 {
       
   743     QTest::addColumn<QAbstractValueSpaceLayer *>("layer");
       
   744 
       
   745     QList<QAbstractValueSpaceLayer *> layers = QValueSpaceManager::instance()->getLayers();
       
   746     for (int i = 0; i < layers.count(); ++i)
       
   747         QTest::newRow(layers.at(i)->name().toLocal8Bit().constData()) << layers.at(i);
       
   748 }
       
   749 
       
   750 void tst_QValueSpaceSubscriber::value()
       
   751 {
       
   752     QFETCH(QAbstractValueSpaceLayer *, layer);
       
   753 
       
   754     QValueSpaceSubscriber base(layer->id(), QString("/"));
       
   755     QCOMPARE(base.value("home/usercount", 5).toInt(), 1);
       
   756     QCOMPARE(base.value("home/user/QString", "default").toString(), QString("testString"));
       
   757     QCOMPARE(base.value("home/user/bool", false).toBool(), true);
       
   758     QCOMPARE(base.value("home/user/int", 5).toInt(), 3);
       
   759     QCOMPARE(base.value("home/user/QByteArray", QByteArray("invalid")).toByteArray(),
       
   760              QByteArray("testByteArray"));
       
   761     QVERIFY(fabs(base.value("home/user/double", 4.0).toDouble() - double(4.56)) < 0.01);
       
   762     //QCOMPARE(base.value("home/user/float", 4.0).toDouble(), (double)4.56);
       
   763 
       
   764     QValueSpaceSubscriber base1(layer->id(), QString("/home"));
       
   765     QCOMPARE(base1.value(QString("usercount"), 5).toInt(), 1);
       
   766     QCOMPARE(base1.value(QString("user/QString"), "default").toString(), QString("testString"));
       
   767     QCOMPARE(base1.value("user/bool", false).toBool(), true);
       
   768     QCOMPARE(base1.value("user/int", 5).toInt(), 3);
       
   769     QCOMPARE(base1.value("user/QByteArray", QByteArray("invalid")).toByteArray(),
       
   770              QByteArray("testByteArray"));
       
   771     QVERIFY(fabs(base.value("home/user/double", 4.0).toDouble() - double(4.56)) < 0.01);
       
   772     //QCOMPARE(base1.value("user/float", 4.0).toDouble(), double(4.56));
       
   773 
       
   774     QValueSpaceSubscriber base2(layer->id(), QString("/home/user"));
       
   775     QCOMPARE(base2.value(QString("usercount"), 5).toInt(), 5);
       
   776     QCOMPARE(base2.value(QString("QString"), "default").toString(), QString("testString"));
       
   777     QCOMPARE(base2.value("bool", false).toBool(), true);
       
   778     QCOMPARE(base2.value("int", 5).toInt(), 3);
       
   779     QCOMPARE(base2.value("QByteArray", QByteArray("invalid")).toByteArray(),
       
   780              QByteArray("testByteArray"));
       
   781     QVERIFY(fabs(base.value("home/user/double", 4.0).toDouble() - double(4.56)) < 0.01);
       
   782     //QCOMPARE(base2.value("float", 4.0).toDouble(), 4.56);
       
   783 }
       
   784 
       
   785 void tst_QValueSpaceSubscriber::ipcTests_data()
       
   786 {
       
   787 #ifdef QT_NO_PROCESS
       
   788     QSKIP("Qt was compiled with QT_NO_PROCESS", SkipAll);
       
   789 #else
       
   790     QTest::addColumn<QAbstractValueSpaceLayer *>("layer");
       
   791 
       
   792     QList<QAbstractValueSpaceLayer *> layers = QValueSpaceManager::instance()->getLayers();
       
   793     for (int i = 0; i < layers.count(); ++i)
       
   794         QTest::newRow(layers.at(i)->name().toLocal8Bit().constData()) << layers.at(i);
       
   795 #endif
       
   796 }
       
   797 
       
   798 void tst_QValueSpaceSubscriber::ipcTests()
       
   799 {
       
   800 #ifdef Q_OS_SYMBIAN
       
   801     QSKIP("No multiple processes in Symbian emulator", SkipAll);
       
   802 #endif
       
   803 
       
   804 #if defined(QT_NO_PROCESS)
       
   805     QSKIP("Qt was compiled with QT_NO_PROCESS", SkipAll);
       
   806 #else
       
   807     QFETCH(QAbstractValueSpaceLayer *, layer);
       
   808 
       
   809     QValueSpaceSubscriber subscriber(layer->id(), "/usr/lackey/subdir/value");
       
   810     ChangeListener listener;
       
   811     QSignalSpy spy(&listener, SIGNAL(baseChanged()));
       
   812     connect(&subscriber, SIGNAL(contentsChanged()), &listener, SIGNAL(baseChanged()));
       
   813 
       
   814     QProcess process;
       
   815     process.setProcessChannelMode(QProcess::ForwardedChannels);
       
   816 #ifdef Q_OS_UNIX
       
   817     process.start("./vsiTestLackey", QStringList() << "-ipcTests" << layer->id().toString());
       
   818 #else
       
   819     process.start("vsiTestLackey", QStringList() << "-ipcTests" << layer->id().toString());
       
   820 #endif
       
   821     QVERIFY(process.waitForStarted());
       
   822 
       
   823     //lackey sets value to 100 as part of its startup
       
   824     QTRY_COMPARE(spy.count(), 1);
       
   825     QCOMPARE(subscriber.value("", 99).toInt(), 100);
       
   826     spy.clear();
       
   827 
       
   828     //lackey sets value to 101
       
   829     QTRY_COMPARE(spy.count(), 1);
       
   830     QCOMPARE(subscriber.value("", 99).toInt(), 101);
       
   831     spy.clear();
       
   832 
       
   833     //value was removed -> returns default
       
   834     QTRY_COMPARE(spy.count(), 1);
       
   835     QCOMPARE(subscriber.value("", 99).toInt(), 99);
       
   836     spy.clear();
       
   837 
       
   838     //lackey sets value to 102
       
   839     QTRY_COMPARE(spy.count(), 1);
       
   840     QCOMPARE(subscriber.value("", 99).toInt(), 102);
       
   841     spy.clear();
       
   842 
       
   843     //value was removed -> returns default
       
   844     QTRY_COMPARE(spy.count(), 1);
       
   845     QCOMPARE(subscriber.value("", 99).toInt(), 99);
       
   846 
       
   847     QVERIFY(process.waitForFinished(10000));
       
   848 #endif
       
   849 }
       
   850 
       
   851 void tst_QValueSpaceSubscriber::ipcRemoveKey_data()
       
   852 {
       
   853 #ifdef QT_NO_PROCESS
       
   854     QSKIP("Qt was compiled with QT_NO_PROCESS", SkipAll);
       
   855 #else
       
   856     QTest::addColumn<QAbstractValueSpaceLayer *>("layer");
       
   857 
       
   858     bool skip = true;
       
   859 
       
   860     QList<QAbstractValueSpaceLayer *> layers = QValueSpaceManager::instance()->getLayers();
       
   861     for (int i = 0; i < layers.count(); ++i) {
       
   862         QAbstractValueSpaceLayer *layer = layers.at(i);
       
   863 
       
   864         if (layer->layerOptions() & QValueSpace::PermanentLayer)
       
   865             continue;
       
   866 
       
   867         skip = false;
       
   868 
       
   869         QTest::newRow(layer->name().toLocal8Bit().constData()) << layer;
       
   870     }
       
   871 
       
   872     if (skip)
       
   873         QSKIP("No applicable layers found.", SkipAll);
       
   874 #endif
       
   875 }
       
   876 
       
   877 void tst_QValueSpaceSubscriber::ipcRemoveKey()
       
   878 {
       
   879 #if defined(QT_NO_PROCESS)
       
   880     QSKIP("Qt was compiled with QT_NO_PROCESS", SkipAll);
       
   881 #else
       
   882     QFETCH(QAbstractValueSpaceLayer *, layer);
       
   883 
       
   884     QValueSpaceSubscriber subscriber(layer->id(), "/ipcRemoveKey");
       
   885 
       
   886     ChangeListener listener;
       
   887     QSignalSpy changeSpy(&listener, SIGNAL(baseChanged()));
       
   888     QObject::connect(&subscriber, SIGNAL(contentsChanged()), &listener, SIGNAL(baseChanged()));
       
   889 
       
   890     QProcess process;
       
   891     process.setProcessChannelMode(QProcess::ForwardedChannels);
       
   892 #ifdef Q_OS_UNIX
       
   893     process.start("./vsiTestLackey", QStringList() << "-ipcRemoveKey" << layer->id().toString());
       
   894 #else
       
   895     process.start("vsiTestLackey", QStringList() << "-ipcRemoveKey" << layer->id().toString());
       
   896 #endif
       
   897     QVERIFY(process.waitForStarted());
       
   898 
       
   899     // Wait for lackey to create "value".
       
   900     QTRY_COMPARE(changeSpy.count(), 1);
       
   901     QCOMPARE(subscriber.value("value", 5).toInt(), 100);
       
   902 
       
   903     // Wait for lackey to delete key "/ipcRemoveKey".
       
   904     changeSpy.clear();
       
   905     QTRY_COMPARE(changeSpy.count(), 1);
       
   906 
       
   907     QVERIFY(subscriber.subPaths().isEmpty());
       
   908     QCOMPARE(subscriber.value("value", 6).toInt(), 6);
       
   909     QVERIFY(process.waitForFinished(10000));
       
   910 #endif
       
   911 }
       
   912 
       
   913 void tst_QValueSpaceSubscriber::interestNotification_data()
       
   914 {
       
   915     QTest::addColumn<QAbstractValueSpaceLayer *>("layer");
       
   916 
       
   917     QTest::addColumn<QString>("publisherPath");
       
   918     QTest::addColumn<QString>("attribute");
       
   919 
       
   920     bool foundSupported = false;
       
   921 
       
   922     QList<QAbstractValueSpaceLayer *> layers = QValueSpaceManager::instance()->getLayers();
       
   923     for (int i = 0; i < layers.count(); ++i) {
       
   924         QAbstractValueSpaceLayer *layer = layers.at(i);
       
   925 
       
   926         if (!layer->supportsInterestNotification())
       
   927             continue;
       
   928 
       
   929         foundSupported = true;
       
   930 
       
   931         QTest::newRow("QValueSpaceSubscriber(QString)")
       
   932             << layer << "/interestNotification" << "/value";
       
   933     }
       
   934 
       
   935     if (!foundSupported)
       
   936         QSKIP("No layer supporting interest notifications found.", SkipAll);
       
   937 }
       
   938 
       
   939 void tst_QValueSpaceSubscriber::interestNotification()
       
   940 {
       
   941     QFETCH(QAbstractValueSpaceLayer *, layer);
       
   942 
       
   943     QFETCH(QString, publisherPath);
       
   944     QFETCH(QString, attribute);
       
   945 
       
   946     QValueSpacePublisher *publisher;
       
   947     publisher = new QValueSpacePublisher(layer->id(), publisherPath);
       
   948 
       
   949     ChangeListener notificationListener;
       
   950     connect(publisher, SIGNAL(interestChanged(QString,bool)),
       
   951             &notificationListener, SIGNAL(interestChanged(QString,bool)));
       
   952 
       
   953     QSignalSpy notificationSpy(&notificationListener,
       
   954                                SIGNAL(interestChanged(QString,bool)));
       
   955 
       
   956     const QString subscriberPath = publisherPath + attribute;
       
   957 
       
   958     QValueSpaceSubscriber *subscriber = new QValueSpaceSubscriber(layer->id(), subscriberPath);
       
   959 
       
   960     QTRY_COMPARE(notificationSpy.count(), 1);
       
   961 
       
   962     QList<QVariant> arguments = notificationSpy.takeFirst();
       
   963     QCOMPARE(arguments.at(0).type(), QVariant::String);
       
   964     QCOMPARE(arguments.at(0).toString(), attribute);
       
   965     QCOMPARE(arguments.at(1).type(), QVariant::Bool);
       
   966     QCOMPARE(arguments.at(1).toBool(), true);
       
   967 
       
   968     QCOMPARE(subscriber->value(QString(), 10).toInt(), 10);
       
   969 
       
   970     publisher->setValue(attribute, 5);
       
   971     publisher->sync();
       
   972 
       
   973     QCOMPARE(subscriber->value(QString(), 10).toInt(), 5);
       
   974 
       
   975     notificationSpy.clear();
       
   976 
       
   977     delete subscriber;
       
   978 
       
   979     QTRY_COMPARE(notificationSpy.count(), 1);
       
   980 
       
   981     arguments = notificationSpy.takeFirst();
       
   982     QCOMPARE(arguments.at(0).type(), QVariant::String);
       
   983     QCOMPARE(arguments.at(0).toString(), attribute);
       
   984     QCOMPARE(arguments.at(1).type(), QVariant::Bool);
       
   985     QCOMPARE(arguments.at(1).toBool(), false);
       
   986 
       
   987     delete publisher;
       
   988 }
       
   989 
       
   990 void tst_QValueSpaceSubscriber::ipcInterestNotification_data()
       
   991 {
       
   992 #ifdef QT_NO_PROCESS
       
   993     QSKIP("Qt was compiled with QT_NO_PROCESS", SkipAll);
       
   994 #else
       
   995     QTest::addColumn<QAbstractValueSpaceLayer *>("layer");
       
   996 
       
   997     bool foundSupported = false;
       
   998 
       
   999     QList<QAbstractValueSpaceLayer *> layers = QValueSpaceManager::instance()->getLayers();
       
  1000     for (int i = 0; i < layers.count(); ++i) {
       
  1001         QAbstractValueSpaceLayer *layer = layers.at(i);
       
  1002 
       
  1003         if (!layer->supportsInterestNotification())
       
  1004             continue;
       
  1005 
       
  1006         foundSupported = true;
       
  1007 
       
  1008         QTest::newRow(layer->name().toLocal8Bit().constData()) << layer;
       
  1009     }
       
  1010 
       
  1011     if (!foundSupported)
       
  1012         QSKIP("No layer supporting interest notifications found.", SkipAll);
       
  1013 #endif
       
  1014 }
       
  1015 
       
  1016 void tst_QValueSpaceSubscriber::ipcInterestNotification()
       
  1017 {
       
  1018 #if defined(QT_NO_PROCESS)
       
  1019     QSKIP("Qt was compiled with QT_NO_PROCESS", SkipAll);
       
  1020 #else
       
  1021     QFETCH(QAbstractValueSpaceLayer *, layer);
       
  1022 
       
  1023     // Test QValueSpaceSubscriber construction before QValueSpacePublisher.
       
  1024 
       
  1025     QValueSpaceSubscriber *subscriber =
       
  1026         new QValueSpaceSubscriber(layer->id(), "/ipcInterestNotification/value");
       
  1027 
       
  1028     ChangeListener listener;
       
  1029     QObject::connect(subscriber, SIGNAL(contentsChanged()), &listener, SIGNAL(baseChanged()));
       
  1030     QSignalSpy changeSpy(&listener, SIGNAL(baseChanged()));
       
  1031 
       
  1032     // Lackey is not running, so value will not exist.
       
  1033     QCOMPARE(subscriber->value(QString(), 10).toInt(), 10);
       
  1034 
       
  1035     QProcess process;
       
  1036     process.setProcessChannelMode(QProcess::ForwardedChannels);
       
  1037 #ifdef Q_OS_UNIX
       
  1038     process.start("./vsiTestLackey", QStringList()
       
  1039         << "-ipcInterestNotification" << layer->id().toString());
       
  1040 #else
       
  1041     process.start("vsiTestLackey", QStringList()
       
  1042         << "-ipcInterestNotification" << layer->id().toString());
       
  1043 #endif
       
  1044     QVERIFY(process.waitForStarted());
       
  1045 
       
  1046     // Lackey will receive interestChanged from server and set the attribute.
       
  1047     QTRY_COMPARE(changeSpy.count(), 1);
       
  1048     changeSpy.clear();
       
  1049 
       
  1050     QCOMPARE(subscriber->value(QString(), 10).toInt(), 5);
       
  1051 
       
  1052     // Lackey will receive interestChanged and remove attribute.
       
  1053     delete subscriber;
       
  1054     QTest::qWait(1000);
       
  1055 
       
  1056     // Test QValueSpaceSubscriber construction after QValueSpacePublisher
       
  1057 
       
  1058     subscriber = new QValueSpaceSubscriber(layer->id(), "/ipcInterestNotification/value");
       
  1059     QObject::connect(subscriber, SIGNAL(contentsChanged()), &listener, SIGNAL(baseChanged()));
       
  1060 
       
  1061     QTRY_COMPARE(changeSpy.count(), 1);
       
  1062 
       
  1063     QCOMPARE(subscriber->value(QString(), 10).toInt(), 5);
       
  1064 #endif
       
  1065 }
       
  1066 
       
  1067 void tst_QValueSpaceSubscriber::clientServer()
       
  1068 {
       
  1069 #if defined(QT_START_VALUESPACE)
       
  1070     QVERIFY(QValueSpaceManager::instance()->isServer());
       
  1071 #else
       
  1072     QVERIFY(!QValueSpaceManager::instance()->isServer());
       
  1073 #endif
       
  1074 }
       
  1075 
       
  1076 class WriteThread : public QThread
       
  1077 {
       
  1078     Q_OBJECT
       
  1079 
       
  1080 public:
       
  1081     WriteThread(const QUuid& layerId);
       
  1082 
       
  1083     void setDone();
       
  1084 
       
  1085 protected:
       
  1086     void run();
       
  1087 
       
  1088 private:
       
  1089     QValueSpacePublisher *publisher;
       
  1090     bool done;
       
  1091     const QUuid& layerId;
       
  1092 };
       
  1093 
       
  1094 WriteThread::WriteThread(const QUuid& layerId)
       
  1095 :   publisher(0), done(false), layerId(layerId)
       
  1096 {
       
  1097 }
       
  1098 
       
  1099 void WriteThread::setDone()
       
  1100 {
       
  1101     done = true;
       
  1102 }
       
  1103 
       
  1104 void WriteThread::run()
       
  1105 {
       
  1106     QTest::qWait(100);  // give some ReadThreads some time to start.
       
  1107 
       
  1108     QValueSpacePublisher publisher(layerId, "/threads");
       
  1109 
       
  1110     uint value = 0;
       
  1111     while (!done) {
       
  1112         publisher.setValue("value", value);
       
  1113         publisher.sync();
       
  1114         QTest::qWait(100);
       
  1115         value += 100;
       
  1116     }
       
  1117 }
       
  1118 
       
  1119 class ReadThread : public QThread
       
  1120 {
       
  1121     Q_OBJECT
       
  1122 
       
  1123 public:
       
  1124     ReadThread(QValueSpaceSubscriber *subscriber, bool sync, const QUuid& layerId);
       
  1125 
       
  1126 protected:
       
  1127     void run();
       
  1128 
       
  1129 private:
       
  1130     QValueSpaceSubscriber *masterSubscriber;
       
  1131     int iterations;
       
  1132     bool synchronised;
       
  1133     const QUuid& layerId;
       
  1134 };
       
  1135 
       
  1136 ReadThread::ReadThread(QValueSpaceSubscriber *subscriber, bool sync, const QUuid& layerId)
       
  1137 :   masterSubscriber(subscriber), iterations(0), synchronised(sync), layerId(layerId)
       
  1138 {
       
  1139 }
       
  1140 
       
  1141 void ReadThread::run()
       
  1142 {
       
  1143     while (true) {
       
  1144         QValueSpaceSubscriber subscriber(layerId, masterSubscriber->path());
       
  1145 
       
  1146         if (synchronised) {
       
  1147             QEventLoop loop;
       
  1148             connect(&subscriber, SIGNAL(contentsChanged()), &loop, SLOT(quit()));
       
  1149             QTimer::singleShot(1000, &loop, SLOT(quit()));
       
  1150             loop.exec();
       
  1151         }
       
  1152 
       
  1153         ++iterations;
       
  1154 
       
  1155         QVariant value = subscriber.value();
       
  1156         if (value.isValid() && value.toUInt() > 1000)
       
  1157             break;
       
  1158     }
       
  1159 }
       
  1160 
       
  1161 void tst_QValueSpaceSubscriber::threads_data()
       
  1162 {
       
  1163     QTest::addColumn<unsigned int>("threads");
       
  1164     QTest::addColumn<bool>("synchronised");
       
  1165     QTest::addColumn<QUuid>("layerId");
       
  1166 
       
  1167     QList<QAbstractValueSpaceLayer *> layers = QValueSpaceManager::instance()->getLayers();
       
  1168 
       
  1169     int foundLayers = 0;
       
  1170     for (int i = 0; i < layers.count(); ++i) {
       
  1171         QAbstractValueSpaceLayer *layer = layers.at(i);
       
  1172 
       
  1173         //GConfLayer can't provide thread-safety because it eventually depends on
       
  1174         //DBus which isn't fully thread-safe
       
  1175         if (layer->id() == QVALUESPACE_GCONF_LAYER) {
       
  1176             continue;
       
  1177         }
       
  1178 
       
  1179         const QUuid id = layer->id();
       
  1180 
       
  1181         QTest::newRow("1 thread") << uint(1) << true << id;
       
  1182         QTest::newRow("2 threads") << uint(2) << true << id;
       
  1183 #if defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN)
       
  1184         QTest::newRow("10 threads") << uint(10) << true << id;
       
  1185 #else
       
  1186         QTest::newRow("100 threads") << uint(100) << true << id;
       
  1187 #endif
       
  1188         QTest::newRow("1 thread, unsynchronised") << uint(1) << false << id;
       
  1189         QTest::newRow("2 threads, unsynchronised") << uint(2) << false << id;
       
  1190 #if defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN)
       
  1191         QTest::newRow("10 threads") << uint(10) << false  << id;
       
  1192 #else
       
  1193         QTest::newRow("100 threads, unsynchronised") << uint(100) << false << id;
       
  1194 #endif
       
  1195         foundLayers++;
       
  1196     }
       
  1197 
       
  1198     if (foundLayers == 0)
       
  1199         QSKIP("No layers providing thread-safety found", SkipAll);
       
  1200 }
       
  1201 
       
  1202 void tst_QValueSpaceSubscriber::threads()
       
  1203 {
       
  1204     QFETCH(unsigned int, threads);
       
  1205     QFETCH(bool, synchronised);
       
  1206     QFETCH(QUuid, layerId);
       
  1207 
       
  1208     QEventLoop writeLoop;
       
  1209     WriteThread *writeThread = new WriteThread(layerId);
       
  1210     connect(writeThread, SIGNAL(finished()), &writeLoop, SLOT(quit()));
       
  1211     writeThread->start();
       
  1212 
       
  1213     QValueSpaceSubscriber masterSubscriber(layerId, "/threads/value");
       
  1214 
       
  1215     QVector<ReadThread *> readThreads(threads);
       
  1216 
       
  1217     for (unsigned int i = 0; i < threads; ++i) {
       
  1218         readThreads[i] = new ReadThread(&masterSubscriber, synchronised, layerId);
       
  1219         readThreads[i]->start();
       
  1220     }
       
  1221 
       
  1222     for (unsigned int i = 0; i < threads; ++i) {
       
  1223         QEventLoop loop;
       
  1224         connect(readThreads[i], SIGNAL(finished()), &loop, SLOT(quit()));
       
  1225         if (!readThreads[i]->isFinished())
       
  1226             loop.exec();
       
  1227 
       
  1228         delete readThreads[i];
       
  1229     }
       
  1230 
       
  1231     writeThread->setDone();
       
  1232 
       
  1233     if (!writeThread->isFinished())
       
  1234         writeLoop.exec();
       
  1235 
       
  1236     delete writeThread;
       
  1237 #ifdef Q_OS_SYMBIAN
       
  1238     QValueSpacePublisher resetPublisher(layerId, "/threads");
       
  1239     resetPublisher.resetValue("value");
       
  1240 #endif
       
  1241 
       
  1242 }
       
  1243 
       
  1244 #include "tst_qvaluespacesubscribershared.moc"