|
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 ¬ificationListener, SIGNAL(interestChanged(QString,bool))); |
|
952 |
|
953 QSignalSpy notificationSpy(¬ificationListener, |
|
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" |