|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 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 test suite of the Qt Toolkit. |
|
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 <QtTest/QtTest> |
|
43 #include <QtCore/QCoreApplication> |
|
44 #include <QtGui/QPushButton> |
|
45 #include <QtGui/QGraphicsScene> |
|
46 #include <QtGui/QGraphicsSceneEvent> |
|
47 #include <QtGui/QGraphicsTextItem> |
|
48 |
|
49 #include "qstatemachine.h" |
|
50 #include "qstate.h" |
|
51 #include "qhistorystate.h" |
|
52 #include "qkeyeventtransition.h" |
|
53 #include "qmouseeventtransition.h" |
|
54 #include "private/qstate_p.h" |
|
55 #include "private/qstatemachine_p.h" |
|
56 |
|
57 // Will try to wait for the condition while allowing event processing |
|
58 #define QTRY_COMPARE(__expr, __expected) \ |
|
59 do { \ |
|
60 const int __step = 50; \ |
|
61 const int __timeout = 5000; \ |
|
62 if ((__expr) != (__expected)) { \ |
|
63 QTest::qWait(0); \ |
|
64 } \ |
|
65 for (int __i = 0; __i < __timeout && ((__expr) != (__expected)); __i+=__step) { \ |
|
66 QTest::qWait(__step); \ |
|
67 } \ |
|
68 QCOMPARE(__expr, __expected); \ |
|
69 } while(0) |
|
70 |
|
71 //TESTED_CLASS= |
|
72 //TESTED_FILES= |
|
73 |
|
74 static int globalTick; |
|
75 |
|
76 // Run exec for a maximum of TIMEOUT msecs |
|
77 #define QCOREAPPLICATION_EXEC(TIMEOUT) \ |
|
78 { \ |
|
79 QTimer timer; \ |
|
80 timer.setSingleShot(true); \ |
|
81 timer.setInterval(TIMEOUT); \ |
|
82 timer.start(); \ |
|
83 connect(&timer, SIGNAL(timeout()), QCoreApplication::instance(), SLOT(quit())); \ |
|
84 QCoreApplication::exec(); \ |
|
85 } |
|
86 |
|
87 class SignalEmitter : public QObject |
|
88 { |
|
89 Q_OBJECT |
|
90 public: |
|
91 SignalEmitter(QObject *parent = 0) |
|
92 : QObject(parent) {} |
|
93 void emitSignalWithNoArg() |
|
94 { emit signalWithNoArg(); } |
|
95 void emitSignalWithIntArg(int arg) |
|
96 { emit signalWithIntArg(arg); } |
|
97 void emitSignalWithStringArg(const QString &arg) |
|
98 { emit signalWithStringArg(arg); } |
|
99 void emitSignalWithDefaultArg() |
|
100 { emit signalWithDefaultArg(); } |
|
101 Q_SIGNALS: |
|
102 void signalWithNoArg(); |
|
103 void signalWithIntArg(int); |
|
104 void signalWithStringArg(const QString &); |
|
105 void signalWithDefaultArg(int i = 42); |
|
106 }; |
|
107 |
|
108 class tst_QStateMachine : public QObject |
|
109 { |
|
110 Q_OBJECT |
|
111 public: |
|
112 tst_QStateMachine(); |
|
113 virtual ~tst_QStateMachine(); |
|
114 |
|
115 private slots: |
|
116 void init(); |
|
117 void cleanup(); |
|
118 |
|
119 void rootState(); |
|
120 void addAndRemoveState(); |
|
121 void stateEntryAndExit(); |
|
122 void assignProperty(); |
|
123 void assignPropertyWithAnimation(); |
|
124 void postEvent(); |
|
125 void cancelDelayedEvent(); |
|
126 void postDelayedEventAndStop(); |
|
127 void stateFinished(); |
|
128 void parallelStates(); |
|
129 void parallelRootState(); |
|
130 void allSourceToTargetConfigurations(); |
|
131 void signalTransitions(); |
|
132 void eventTransitions(); |
|
133 void graphicsSceneEventTransitions(); |
|
134 void historyStates(); |
|
135 void startAndStop(); |
|
136 void targetStateWithNoParent(); |
|
137 void targetStateDeleted(); |
|
138 void transitionToRootState(); |
|
139 void transitionFromRootState(); |
|
140 void transitionEntersParent(); |
|
141 |
|
142 void defaultErrorState(); |
|
143 void customGlobalErrorState(); |
|
144 void customLocalErrorStateInBrokenState(); |
|
145 void customLocalErrorStateInOtherState(); |
|
146 void customLocalErrorStateInParentOfBrokenState(); |
|
147 void customLocalErrorStateOverridesParent(); |
|
148 void errorStateHasChildren(); |
|
149 void errorStateHasErrors(); |
|
150 void errorStateIsRootState(); |
|
151 void errorStateEntersParentFirst(); |
|
152 void customErrorStateIsNull(); |
|
153 void clearError(); |
|
154 void historyStateHasNowhereToGo(); |
|
155 void historyStateAsInitialState(); |
|
156 void brokenStateIsNeverEntered(); |
|
157 void customErrorStateNotInGraph(); |
|
158 void transitionToStateNotInGraph(); |
|
159 void restoreProperties(); |
|
160 |
|
161 void defaultGlobalRestorePolicy(); |
|
162 void globalRestorePolicySetToRestore(); |
|
163 void globalRestorePolicySetToDoNotRestore(); |
|
164 |
|
165 void noInitialStateForInitialState(); |
|
166 |
|
167 //void restorePolicyNotInherited(); |
|
168 //void mixedRestoreProperties(); |
|
169 //void setRestorePolicyToDoNotRestore(); |
|
170 //void setGlobalRestorePolicyToGlobalRestore(); |
|
171 //void restorePolicyOnChildState(); |
|
172 |
|
173 void transitionWithParent(); |
|
174 void transitionsFromParallelStateWithNoChildren(); |
|
175 void parallelStateTransition(); |
|
176 void parallelStateAssignmentsDone(); |
|
177 void nestedRestoreProperties(); |
|
178 void nestedRestoreProperties2(); |
|
179 |
|
180 void simpleAnimation(); |
|
181 void twoAnimations(); |
|
182 void twoAnimatedTransitions(); |
|
183 void playAnimationTwice(); |
|
184 void nestedTargetStateForAnimation(); |
|
185 void polishedSignalTransitionsReuseAnimationGroup(); |
|
186 void animatedGlobalRestoreProperty(); |
|
187 void specificTargetValueOfAnimation(); |
|
188 |
|
189 void addDefaultAnimation(); |
|
190 void addDefaultAnimationWithUnusedAnimation(); |
|
191 void removeDefaultAnimation(); |
|
192 void overrideDefaultAnimationWithSpecific(); |
|
193 |
|
194 // void addDefaultAnimationForSource(); |
|
195 // void addDefaultAnimationForTarget(); |
|
196 // void removeDefaultAnimationForSource(); |
|
197 // void removeDefaultAnimationForTarget(); |
|
198 // void overrideDefaultAnimationWithSource(); |
|
199 // void overrideDefaultAnimationWithTarget(); |
|
200 // void overrideDefaultSourceAnimationWithSpecific(); |
|
201 // void overrideDefaultTargetAnimationWithSpecific(); |
|
202 // void overrideDefaultTargetAnimationWithSource(); |
|
203 |
|
204 void nestedStateMachines(); |
|
205 void goToState(); |
|
206 |
|
207 void task260403_clonedSignals(); |
|
208 }; |
|
209 |
|
210 tst_QStateMachine::tst_QStateMachine() |
|
211 { |
|
212 } |
|
213 |
|
214 tst_QStateMachine::~tst_QStateMachine() |
|
215 { |
|
216 } |
|
217 |
|
218 class TestState : public QState |
|
219 { |
|
220 public: |
|
221 enum Event { |
|
222 Entry, |
|
223 Exit |
|
224 }; |
|
225 TestState(QState *parent) |
|
226 : QState(parent) {} |
|
227 QList<QPair<int, Event> > events; |
|
228 protected: |
|
229 virtual void onEntry(QEvent *) { |
|
230 events.append(qMakePair(globalTick++, Entry)); |
|
231 } |
|
232 virtual void onExit(QEvent *) { |
|
233 events.append(qMakePair(globalTick++, Exit)); |
|
234 } |
|
235 }; |
|
236 |
|
237 class TestTransition : public QAbstractTransition |
|
238 { |
|
239 public: |
|
240 TestTransition(QAbstractState *target) |
|
241 : QAbstractTransition() |
|
242 { setTargetState(target); } |
|
243 QList<int> triggers; |
|
244 protected: |
|
245 virtual bool eventTest(QEvent *) { |
|
246 return true; |
|
247 } |
|
248 virtual void onTransition(QEvent *) { |
|
249 triggers.append(globalTick++); |
|
250 } |
|
251 }; |
|
252 |
|
253 void tst_QStateMachine::init() |
|
254 { |
|
255 } |
|
256 |
|
257 void tst_QStateMachine::cleanup() |
|
258 { |
|
259 } |
|
260 |
|
261 class EventTransition : public QAbstractTransition |
|
262 { |
|
263 public: |
|
264 EventTransition(QEvent::Type type, QAbstractState *target, QState *parent = 0) |
|
265 : QAbstractTransition(parent), m_type(type) |
|
266 { setTargetState(target); } |
|
267 protected: |
|
268 virtual bool eventTest(QEvent *e) { |
|
269 return (e->type() == m_type); |
|
270 } |
|
271 virtual void onTransition(QEvent *) {} |
|
272 private: |
|
273 QEvent::Type m_type; |
|
274 }; |
|
275 |
|
276 void tst_QStateMachine::transitionToRootState() |
|
277 { |
|
278 QStateMachine machine; |
|
279 machine.setObjectName("machine"); |
|
280 |
|
281 QState *initialState = new QState(); |
|
282 initialState->setObjectName("initial"); |
|
283 machine.addState(initialState); |
|
284 machine.setInitialState(initialState); |
|
285 |
|
286 QAbstractTransition *trans = initialState->addTransition(new EventTransition(QEvent::User, &machine)); |
|
287 QVERIFY(trans != 0); |
|
288 QCOMPARE(trans->sourceState(), initialState); |
|
289 QCOMPARE(trans->targetState(), static_cast<QAbstractState *>(&machine)); |
|
290 |
|
291 machine.start(); |
|
292 QCoreApplication::processEvents(); |
|
293 |
|
294 QCOMPARE(machine.configuration().count(), 1); |
|
295 QVERIFY(machine.configuration().contains(initialState)); |
|
296 |
|
297 machine.postEvent(new QEvent(QEvent::User)); |
|
298 QTest::ignoreMessage(QtWarningMsg, "Unrecoverable error detected in running state machine: No common ancestor for targets and source of transition from state 'initial'"); |
|
299 QCoreApplication::processEvents(); |
|
300 QVERIFY(machine.configuration().isEmpty()); |
|
301 QVERIFY(!machine.isRunning()); |
|
302 } |
|
303 |
|
304 void tst_QStateMachine::transitionFromRootState() |
|
305 { |
|
306 QStateMachine machine; |
|
307 QState *root = &machine; |
|
308 QState *s1 = new QState(root); |
|
309 EventTransition *trans = new EventTransition(QEvent::User, s1); |
|
310 QCOMPARE(root->addTransition(trans), static_cast<QAbstractTransition *>(trans)); |
|
311 QCOMPARE(trans->sourceState(), root); |
|
312 QCOMPARE(trans->targetState(), static_cast<QAbstractState *>(s1)); |
|
313 } |
|
314 |
|
315 void tst_QStateMachine::transitionEntersParent() |
|
316 { |
|
317 QStateMachine machine; |
|
318 |
|
319 QObject *entryController = new QObject(&machine); |
|
320 entryController->setObjectName("entryController"); |
|
321 entryController->setProperty("greatGrandParentEntered", false); |
|
322 entryController->setProperty("grandParentEntered", false); |
|
323 entryController->setProperty("parentEntered", false); |
|
324 entryController->setProperty("stateEntered", false); |
|
325 |
|
326 QState *greatGrandParent = new QState(); |
|
327 greatGrandParent->setObjectName("grandParent"); |
|
328 greatGrandParent->assignProperty(entryController, "greatGrandParentEntered", true); |
|
329 machine.addState(greatGrandParent); |
|
330 machine.setInitialState(greatGrandParent); |
|
331 |
|
332 QState *grandParent = new QState(greatGrandParent); |
|
333 grandParent->setObjectName("grandParent"); |
|
334 grandParent->assignProperty(entryController, "grandParentEntered", true); |
|
335 |
|
336 QState *parent = new QState(grandParent); |
|
337 parent->setObjectName("parent"); |
|
338 parent->assignProperty(entryController, "parentEntered", true); |
|
339 |
|
340 QState *state = new QState(parent); |
|
341 state->setObjectName("state"); |
|
342 state->assignProperty(entryController, "stateEntered", true); |
|
343 |
|
344 QState *initialStateOfGreatGrandParent = new QState(greatGrandParent); |
|
345 initialStateOfGreatGrandParent->setObjectName("initialStateOfGreatGrandParent"); |
|
346 greatGrandParent->setInitialState(initialStateOfGreatGrandParent); |
|
347 |
|
348 initialStateOfGreatGrandParent->addTransition(new EventTransition(QEvent::User, state)); |
|
349 |
|
350 machine.start(); |
|
351 QCoreApplication::processEvents(); |
|
352 |
|
353 QCOMPARE(entryController->property("greatGrandParentEntered").toBool(), true); |
|
354 QCOMPARE(entryController->property("grandParentEntered").toBool(), false); |
|
355 QCOMPARE(entryController->property("parentEntered").toBool(), false); |
|
356 QCOMPARE(entryController->property("stateEntered").toBool(), false); |
|
357 QCOMPARE(machine.configuration().count(), 2); |
|
358 QVERIFY(machine.configuration().contains(greatGrandParent)); |
|
359 QVERIFY(machine.configuration().contains(initialStateOfGreatGrandParent)); |
|
360 |
|
361 entryController->setProperty("greatGrandParentEntered", false); |
|
362 entryController->setProperty("grandParentEntered", false); |
|
363 entryController->setProperty("parentEntered", false); |
|
364 entryController->setProperty("stateEntered", false); |
|
365 |
|
366 machine.postEvent(new QEvent(QEvent::User)); |
|
367 QCoreApplication::processEvents(); |
|
368 |
|
369 QCOMPARE(entryController->property("greatGrandParentEntered").toBool(), false); |
|
370 QCOMPARE(entryController->property("grandParentEntered").toBool(), true); |
|
371 QCOMPARE(entryController->property("parentEntered").toBool(), true); |
|
372 QCOMPARE(entryController->property("stateEntered").toBool(), true); |
|
373 QCOMPARE(machine.configuration().count(), 4); |
|
374 QVERIFY(machine.configuration().contains(greatGrandParent)); |
|
375 QVERIFY(machine.configuration().contains(grandParent)); |
|
376 QVERIFY(machine.configuration().contains(parent)); |
|
377 QVERIFY(machine.configuration().contains(state)); |
|
378 } |
|
379 |
|
380 void tst_QStateMachine::defaultErrorState() |
|
381 { |
|
382 QStateMachine machine; |
|
383 QCOMPARE(machine.errorState(), reinterpret_cast<QAbstractState *>(0)); |
|
384 |
|
385 QState *brokenState = new QState(); |
|
386 brokenState->setObjectName("MyInitialState"); |
|
387 |
|
388 machine.addState(brokenState); |
|
389 machine.setInitialState(brokenState); |
|
390 |
|
391 QState *childState = new QState(brokenState); |
|
392 childState->setObjectName("childState"); |
|
393 |
|
394 QTest::ignoreMessage(QtWarningMsg, "Unrecoverable error detected in running state machine: Missing initial state in compound state 'MyInitialState'"); |
|
395 |
|
396 // initialState has no initial state |
|
397 machine.start(); |
|
398 QCoreApplication::processEvents(); |
|
399 |
|
400 QCOMPARE(machine.error(), QStateMachine::NoInitialStateError); |
|
401 QCOMPARE(machine.errorString(), QString::fromLatin1("Missing initial state in compound state 'MyInitialState'")); |
|
402 QCOMPARE(machine.isRunning(), false); |
|
403 } |
|
404 |
|
405 class CustomErrorState: public QState |
|
406 { |
|
407 public: |
|
408 CustomErrorState(QStateMachine *machine, QState *parent = 0) |
|
409 : QState(parent), error(QStateMachine::NoError), m_machine(machine) |
|
410 { |
|
411 } |
|
412 |
|
413 void onEntry(QEvent *) |
|
414 { |
|
415 error = m_machine->error(); |
|
416 errorString = m_machine->errorString(); |
|
417 } |
|
418 |
|
419 QStateMachine::Error error; |
|
420 QString errorString; |
|
421 |
|
422 private: |
|
423 QStateMachine *m_machine; |
|
424 }; |
|
425 |
|
426 void tst_QStateMachine::customGlobalErrorState() |
|
427 { |
|
428 QStateMachine machine; |
|
429 |
|
430 CustomErrorState *customErrorState = new CustomErrorState(&machine); |
|
431 customErrorState->setObjectName("customErrorState"); |
|
432 machine.addState(customErrorState); |
|
433 machine.setErrorState(customErrorState); |
|
434 |
|
435 QState *initialState = new QState(); |
|
436 initialState->setObjectName("initialState"); |
|
437 machine.addState(initialState); |
|
438 machine.setInitialState(initialState); |
|
439 |
|
440 QState *brokenState = new QState(); |
|
441 brokenState->setObjectName("brokenState"); |
|
442 machine.addState(brokenState); |
|
443 QState *childState = new QState(brokenState); |
|
444 childState->setObjectName("childState"); |
|
445 |
|
446 initialState->addTransition(new EventTransition(QEvent::Type(QEvent::User + 1), brokenState)); |
|
447 machine.start(); |
|
448 QCoreApplication::processEvents(); |
|
449 |
|
450 QCOMPARE(machine.errorState(), static_cast<QAbstractState*>(customErrorState)); |
|
451 QCOMPARE(machine.configuration().count(), 1); |
|
452 QVERIFY(machine.configuration().contains(initialState)); |
|
453 |
|
454 machine.postEvent(new QEvent(QEvent::Type(QEvent::User + 1))); |
|
455 QCOMPARE(machine.configuration().count(), 1); |
|
456 QVERIFY(machine.configuration().contains(initialState)); |
|
457 |
|
458 QCoreApplication::processEvents(); |
|
459 |
|
460 QCOMPARE(machine.isRunning(), true); |
|
461 QCOMPARE(machine.configuration().count(), 1); |
|
462 QVERIFY(machine.configuration().contains(customErrorState)); |
|
463 QCOMPARE(customErrorState->error, QStateMachine::NoInitialStateError); |
|
464 QCOMPARE(customErrorState->errorString, QString::fromLatin1("Missing initial state in compound state 'brokenState'")); |
|
465 QCOMPARE(machine.error(), QStateMachine::NoInitialStateError); |
|
466 QCOMPARE(machine.errorString(), QString::fromLatin1("Missing initial state in compound state 'brokenState'")); |
|
467 } |
|
468 |
|
469 void tst_QStateMachine::customLocalErrorStateInBrokenState() |
|
470 { |
|
471 QStateMachine machine; |
|
472 CustomErrorState *customErrorState = new CustomErrorState(&machine); |
|
473 machine.addState(customErrorState); |
|
474 |
|
475 QState *initialState = new QState(); |
|
476 initialState->setObjectName("initialState"); |
|
477 machine.addState(initialState); |
|
478 machine.setInitialState(initialState); |
|
479 |
|
480 QState *brokenState = new QState(); |
|
481 brokenState->setObjectName("brokenState"); |
|
482 machine.addState(brokenState); |
|
483 brokenState->setErrorState(customErrorState); |
|
484 |
|
485 QState *childState = new QState(brokenState); |
|
486 childState->setObjectName("childState"); |
|
487 |
|
488 initialState->addTransition(new EventTransition(QEvent::Type(QEvent::User + 1), brokenState)); |
|
489 |
|
490 machine.start(); |
|
491 QCoreApplication::processEvents(); |
|
492 |
|
493 machine.postEvent(new QEvent(QEvent::Type(QEvent::User + 1))); |
|
494 QCoreApplication::processEvents(); |
|
495 |
|
496 QCOMPARE(machine.isRunning(), true); |
|
497 QCOMPARE(machine.configuration().count(), 1); |
|
498 QVERIFY(machine.configuration().contains(customErrorState)); |
|
499 QCOMPARE(customErrorState->error, QStateMachine::NoInitialStateError); |
|
500 } |
|
501 |
|
502 void tst_QStateMachine::customLocalErrorStateInOtherState() |
|
503 { |
|
504 QStateMachine machine; |
|
505 CustomErrorState *customErrorState = new CustomErrorState(&machine); |
|
506 machine.addState(customErrorState); |
|
507 |
|
508 QState *initialState = new QState(); |
|
509 initialState->setObjectName("initialState"); |
|
510 QTest::ignoreMessage(QtWarningMsg, "QState::setErrorState: error state cannot belong to a different state machine"); |
|
511 initialState->setErrorState(customErrorState); |
|
512 machine.addState(initialState); |
|
513 machine.setInitialState(initialState); |
|
514 |
|
515 QState *brokenState = new QState(); |
|
516 brokenState->setObjectName("brokenState"); |
|
517 |
|
518 machine.addState(brokenState); |
|
519 |
|
520 QState *childState = new QState(brokenState); |
|
521 childState->setObjectName("childState"); |
|
522 |
|
523 initialState->addTransition(new EventTransition(QEvent::Type(QEvent::User + 1), brokenState)); |
|
524 |
|
525 QTest::ignoreMessage(QtWarningMsg, "Unrecoverable error detected in running state machine: Missing initial state in compound state 'brokenState'"); |
|
526 machine.start(); |
|
527 QCoreApplication::processEvents(); |
|
528 |
|
529 machine.postEvent(new QEvent(QEvent::Type(QEvent::User + 1))); |
|
530 QCoreApplication::processEvents(); |
|
531 |
|
532 QCOMPARE(machine.isRunning(), false); |
|
533 } |
|
534 |
|
535 void tst_QStateMachine::customLocalErrorStateInParentOfBrokenState() |
|
536 { |
|
537 QStateMachine machine; |
|
538 CustomErrorState *customErrorState = new CustomErrorState(&machine); |
|
539 machine.addState(customErrorState); |
|
540 |
|
541 QState *initialState = new QState(); |
|
542 initialState->setObjectName("initialState"); |
|
543 machine.addState(initialState); |
|
544 machine.setInitialState(initialState); |
|
545 |
|
546 QState *parentOfBrokenState = new QState(); |
|
547 machine.addState(parentOfBrokenState); |
|
548 parentOfBrokenState->setObjectName("parentOfBrokenState"); |
|
549 parentOfBrokenState->setErrorState(customErrorState); |
|
550 |
|
551 QState *brokenState = new QState(parentOfBrokenState); |
|
552 brokenState->setObjectName("brokenState"); |
|
553 parentOfBrokenState->setInitialState(brokenState); |
|
554 |
|
555 QState *childState = new QState(brokenState); |
|
556 childState->setObjectName("childState"); |
|
557 |
|
558 initialState->addTransition(new EventTransition(QEvent::Type(QEvent::User + 1), brokenState)); |
|
559 |
|
560 machine.start(); |
|
561 QCoreApplication::processEvents(); |
|
562 |
|
563 machine.postEvent(new QEvent(QEvent::Type(QEvent::User + 1))); |
|
564 QCoreApplication::processEvents(); |
|
565 |
|
566 QCOMPARE(machine.isRunning(), true); |
|
567 QCOMPARE(machine.configuration().count(), 1); |
|
568 QVERIFY(machine.configuration().contains(customErrorState)); |
|
569 } |
|
570 |
|
571 void tst_QStateMachine::customLocalErrorStateOverridesParent() |
|
572 { |
|
573 QStateMachine machine; |
|
574 CustomErrorState *customErrorStateForParent = new CustomErrorState(&machine); |
|
575 machine.addState(customErrorStateForParent); |
|
576 |
|
577 CustomErrorState *customErrorStateForBrokenState = new CustomErrorState(&machine); |
|
578 machine.addState(customErrorStateForBrokenState); |
|
579 |
|
580 QState *initialState = new QState(); |
|
581 initialState->setObjectName("initialState"); |
|
582 machine.addState(initialState); |
|
583 machine.setInitialState(initialState); |
|
584 |
|
585 QState *parentOfBrokenState = new QState(); |
|
586 machine.addState(parentOfBrokenState); |
|
587 parentOfBrokenState->setObjectName("parentOfBrokenState"); |
|
588 parentOfBrokenState->setErrorState(customErrorStateForParent); |
|
589 |
|
590 QState *brokenState = new QState(parentOfBrokenState); |
|
591 brokenState->setObjectName("brokenState"); |
|
592 brokenState->setErrorState(customErrorStateForBrokenState); |
|
593 parentOfBrokenState->setInitialState(brokenState); |
|
594 |
|
595 QState *childState = new QState(brokenState); |
|
596 childState->setObjectName("childState"); |
|
597 |
|
598 initialState->addTransition(new EventTransition(QEvent::Type(QEvent::User + 1), brokenState)); |
|
599 |
|
600 machine.start(); |
|
601 QCoreApplication::processEvents(); |
|
602 |
|
603 machine.postEvent(new QEvent(QEvent::Type(QEvent::User + 1))); |
|
604 QCoreApplication::processEvents(); |
|
605 |
|
606 QCOMPARE(machine.configuration().count(), 1); |
|
607 QVERIFY(machine.configuration().contains(customErrorStateForBrokenState)); |
|
608 QCOMPARE(customErrorStateForBrokenState->error, QStateMachine::NoInitialStateError); |
|
609 QCOMPARE(customErrorStateForParent->error, QStateMachine::NoError); |
|
610 } |
|
611 |
|
612 void tst_QStateMachine::errorStateHasChildren() |
|
613 { |
|
614 QStateMachine machine; |
|
615 CustomErrorState *customErrorState = new CustomErrorState(&machine); |
|
616 customErrorState->setObjectName("customErrorState"); |
|
617 machine.addState(customErrorState); |
|
618 |
|
619 machine.setErrorState(customErrorState); |
|
620 |
|
621 QState *childOfErrorState = new QState(customErrorState); |
|
622 childOfErrorState->setObjectName("childOfErrorState"); |
|
623 customErrorState->setInitialState(childOfErrorState); |
|
624 |
|
625 QState *initialState = new QState(); |
|
626 initialState->setObjectName("initialState"); |
|
627 machine.addState(initialState); |
|
628 machine.setInitialState(initialState); |
|
629 |
|
630 QState *brokenState = new QState(); |
|
631 brokenState->setObjectName("brokenState"); |
|
632 machine.addState(brokenState); |
|
633 |
|
634 QState *childState = new QState(brokenState); |
|
635 childState->setObjectName("childState"); |
|
636 |
|
637 initialState->addTransition(new EventTransition(QEvent::Type(QEvent::User + 1), brokenState)); |
|
638 |
|
639 machine.start(); |
|
640 QCoreApplication::processEvents(); |
|
641 |
|
642 machine.postEvent(new QEvent(QEvent::Type(QEvent::User + 1))); |
|
643 QCoreApplication::processEvents(); |
|
644 |
|
645 QCOMPARE(machine.isRunning(), true); |
|
646 QCOMPARE(machine.configuration().count(), 2); |
|
647 QVERIFY(machine.configuration().contains(customErrorState)); |
|
648 QVERIFY(machine.configuration().contains(childOfErrorState)); |
|
649 } |
|
650 |
|
651 |
|
652 void tst_QStateMachine::errorStateHasErrors() |
|
653 { |
|
654 QStateMachine machine; |
|
655 CustomErrorState *customErrorState = new CustomErrorState(&machine); |
|
656 customErrorState->setObjectName("customErrorState"); |
|
657 machine.addState(customErrorState); |
|
658 |
|
659 machine.setErrorState(customErrorState); |
|
660 |
|
661 QState *childOfErrorState = new QState(customErrorState); |
|
662 childOfErrorState->setObjectName("childOfErrorState"); |
|
663 |
|
664 QState *initialState = new QState(); |
|
665 initialState->setObjectName("initialState"); |
|
666 machine.addState(initialState); |
|
667 machine.setInitialState(initialState); |
|
668 |
|
669 QState *brokenState = new QState(); |
|
670 brokenState->setObjectName("brokenState"); |
|
671 machine.addState(brokenState); |
|
672 |
|
673 QState *childState = new QState(brokenState); |
|
674 childState->setObjectName("childState"); |
|
675 |
|
676 initialState->addTransition(new EventTransition(QEvent::Type(QEvent::User + 1), brokenState)); |
|
677 |
|
678 machine.start(); |
|
679 QCoreApplication::processEvents(); |
|
680 |
|
681 machine.postEvent(new QEvent(QEvent::Type(QEvent::User + 1))); |
|
682 QTest::ignoreMessage(QtWarningMsg, "Unrecoverable error detected in running state machine: Missing initial state in compound state 'customErrorState'"); |
|
683 QCoreApplication::processEvents(); |
|
684 |
|
685 QCOMPARE(machine.isRunning(), false); |
|
686 QCOMPARE(machine.error(), QStateMachine::NoInitialStateError); |
|
687 QCOMPARE(machine.errorString(), QString::fromLatin1("Missing initial state in compound state 'customErrorState'")); |
|
688 } |
|
689 |
|
690 void tst_QStateMachine::errorStateIsRootState() |
|
691 { |
|
692 QStateMachine machine; |
|
693 QTest::ignoreMessage(QtWarningMsg, "QStateMachine::setErrorState: root state cannot be error state"); |
|
694 machine.setErrorState(&machine); |
|
695 |
|
696 QState *initialState = new QState(); |
|
697 initialState->setObjectName("initialState"); |
|
698 machine.addState(initialState); |
|
699 machine.setInitialState(initialState); |
|
700 |
|
701 QState *brokenState = new QState(); |
|
702 brokenState->setObjectName("brokenState"); |
|
703 machine.addState(brokenState); |
|
704 |
|
705 QState *childState = new QState(brokenState); |
|
706 childState->setObjectName("childState"); |
|
707 |
|
708 initialState->addTransition(new EventTransition(QEvent::Type(QEvent::User + 1), brokenState)); |
|
709 |
|
710 machine.start(); |
|
711 QCoreApplication::processEvents(); |
|
712 |
|
713 machine.postEvent(new QEvent(QEvent::Type(QEvent::User + 1))); |
|
714 QTest::ignoreMessage(QtWarningMsg, "Unrecoverable error detected in running state machine: Missing initial state in compound state 'brokenState'"); |
|
715 QCoreApplication::processEvents(); |
|
716 |
|
717 QCOMPARE(machine.isRunning(), false); |
|
718 } |
|
719 |
|
720 void tst_QStateMachine::errorStateEntersParentFirst() |
|
721 { |
|
722 QStateMachine machine; |
|
723 |
|
724 QObject *entryController = new QObject(&machine); |
|
725 entryController->setObjectName("entryController"); |
|
726 entryController->setProperty("greatGrandParentEntered", false); |
|
727 entryController->setProperty("grandParentEntered", false); |
|
728 entryController->setProperty("parentEntered", false); |
|
729 entryController->setProperty("errorStateEntered", false); |
|
730 |
|
731 QState *greatGrandParent = new QState(); |
|
732 greatGrandParent->setObjectName("greatGrandParent"); |
|
733 greatGrandParent->assignProperty(entryController, "greatGrandParentEntered", true); |
|
734 machine.addState(greatGrandParent); |
|
735 machine.setInitialState(greatGrandParent); |
|
736 |
|
737 QState *grandParent = new QState(greatGrandParent); |
|
738 grandParent->setObjectName("grandParent"); |
|
739 grandParent->assignProperty(entryController, "grandParentEntered", true); |
|
740 |
|
741 QState *parent = new QState(grandParent); |
|
742 parent->setObjectName("parent"); |
|
743 parent->assignProperty(entryController, "parentEntered", true); |
|
744 |
|
745 QState *errorState = new QState(parent); |
|
746 errorState->setObjectName("errorState"); |
|
747 errorState->assignProperty(entryController, "errorStateEntered", true); |
|
748 machine.setErrorState(errorState); |
|
749 |
|
750 QState *initialStateOfGreatGrandParent = new QState(greatGrandParent); |
|
751 initialStateOfGreatGrandParent->setObjectName("initialStateOfGreatGrandParent"); |
|
752 greatGrandParent->setInitialState(initialStateOfGreatGrandParent); |
|
753 |
|
754 QState *brokenState = new QState(greatGrandParent); |
|
755 brokenState->setObjectName("brokenState"); |
|
756 |
|
757 QState *childState = new QState(brokenState); |
|
758 childState->setObjectName("childState"); |
|
759 |
|
760 initialStateOfGreatGrandParent->addTransition(new EventTransition(QEvent::User, brokenState)); |
|
761 |
|
762 machine.start(); |
|
763 QCoreApplication::processEvents(); |
|
764 |
|
765 QCOMPARE(entryController->property("greatGrandParentEntered").toBool(), true); |
|
766 QCOMPARE(entryController->property("grandParentEntered").toBool(), false); |
|
767 QCOMPARE(entryController->property("parentEntered").toBool(), false); |
|
768 QCOMPARE(entryController->property("errorStateEntered").toBool(), false); |
|
769 QCOMPARE(machine.configuration().count(), 2); |
|
770 QVERIFY(machine.configuration().contains(greatGrandParent)); |
|
771 QVERIFY(machine.configuration().contains(initialStateOfGreatGrandParent)); |
|
772 |
|
773 entryController->setProperty("greatGrandParentEntered", false); |
|
774 entryController->setProperty("grandParentEntered", false); |
|
775 entryController->setProperty("parentEntered", false); |
|
776 entryController->setProperty("errorStateEntered", false); |
|
777 |
|
778 machine.postEvent(new QEvent(QEvent::User)); |
|
779 QCoreApplication::processEvents(); |
|
780 |
|
781 QCOMPARE(entryController->property("greatGrandParentEntered").toBool(), false); |
|
782 QCOMPARE(entryController->property("grandParentEntered").toBool(), true); |
|
783 QCOMPARE(entryController->property("parentEntered").toBool(), true); |
|
784 QCOMPARE(entryController->property("errorStateEntered").toBool(), true); |
|
785 QCOMPARE(machine.configuration().count(), 4); |
|
786 QVERIFY(machine.configuration().contains(greatGrandParent)); |
|
787 QVERIFY(machine.configuration().contains(grandParent)); |
|
788 QVERIFY(machine.configuration().contains(parent)); |
|
789 QVERIFY(machine.configuration().contains(errorState)); |
|
790 } |
|
791 |
|
792 void tst_QStateMachine::customErrorStateIsNull() |
|
793 { |
|
794 QStateMachine machine; |
|
795 machine.setErrorState(0); |
|
796 |
|
797 QState *initialState = new QState(); |
|
798 machine.addState(initialState); |
|
799 machine.setInitialState(initialState); |
|
800 |
|
801 QState *brokenState = new QState(); |
|
802 machine.addState(brokenState); |
|
803 |
|
804 new QState(brokenState); |
|
805 initialState->addTransition(new EventTransition(QEvent::User, brokenState)); |
|
806 |
|
807 machine.start(); |
|
808 QCoreApplication::processEvents(); |
|
809 |
|
810 machine.postEvent(new QEvent(QEvent::User)); |
|
811 QTest::ignoreMessage(QtWarningMsg, "Unrecoverable error detected in running state machine: Missing initial state in compound state ''"); |
|
812 QCoreApplication::processEvents(); |
|
813 |
|
814 QCOMPARE(machine.errorState(), reinterpret_cast<QAbstractState *>(0)); |
|
815 QCOMPARE(machine.isRunning(), false); |
|
816 } |
|
817 |
|
818 void tst_QStateMachine::clearError() |
|
819 { |
|
820 QStateMachine machine; |
|
821 machine.setErrorState(new QState(&machine)); // avoid warnings |
|
822 |
|
823 QState *brokenState = new QState(&machine); |
|
824 brokenState->setObjectName("brokenState"); |
|
825 machine.setInitialState(brokenState); |
|
826 new QState(brokenState); |
|
827 |
|
828 machine.start(); |
|
829 QCoreApplication::processEvents(); |
|
830 |
|
831 QCOMPARE(machine.isRunning(), true); |
|
832 QCOMPARE(machine.error(), QStateMachine::NoInitialStateError); |
|
833 QCOMPARE(machine.errorString(), QString::fromLatin1("Missing initial state in compound state 'brokenState'")); |
|
834 |
|
835 machine.clearError(); |
|
836 |
|
837 QCOMPARE(machine.error(), QStateMachine::NoError); |
|
838 QVERIFY(machine.errorString().isEmpty()); |
|
839 } |
|
840 |
|
841 void tst_QStateMachine::historyStateAsInitialState() |
|
842 { |
|
843 QStateMachine machine; |
|
844 |
|
845 QHistoryState *hs = new QHistoryState(&machine); |
|
846 machine.setInitialState(hs); |
|
847 |
|
848 QState *s1 = new QState(&machine); |
|
849 hs->setDefaultState(s1); |
|
850 |
|
851 QState *s2 = new QState(&machine); |
|
852 |
|
853 QHistoryState *s2h = new QHistoryState(s2); |
|
854 s2->setInitialState(s2h); |
|
855 |
|
856 QState *s21 = new QState(s2); |
|
857 s2h->setDefaultState(s21); |
|
858 |
|
859 s1->addTransition(new EventTransition(QEvent::User, s2)); |
|
860 |
|
861 machine.start(); |
|
862 QCoreApplication::processEvents(); |
|
863 |
|
864 QCOMPARE(machine.configuration().size(), 1); |
|
865 QVERIFY(machine.configuration().contains(s1)); |
|
866 |
|
867 machine.postEvent(new QEvent(QEvent::User)); |
|
868 QCoreApplication::processEvents(); |
|
869 |
|
870 QCOMPARE(machine.configuration().size(), 2); |
|
871 QVERIFY(machine.configuration().contains(s2)); |
|
872 QVERIFY(machine.configuration().contains(s21)); |
|
873 } |
|
874 |
|
875 void tst_QStateMachine::historyStateHasNowhereToGo() |
|
876 { |
|
877 QStateMachine machine; |
|
878 |
|
879 QState *initialState = new QState(&machine); |
|
880 machine.setInitialState(initialState); |
|
881 machine.setErrorState(new QState(&machine)); // avoid warnings |
|
882 |
|
883 QState *brokenState = new QState(&machine); |
|
884 brokenState->setObjectName("brokenState"); |
|
885 brokenState->setInitialState(new QState(brokenState)); |
|
886 |
|
887 QHistoryState *historyState = new QHistoryState(brokenState); |
|
888 historyState->setObjectName("historyState"); |
|
889 initialState->addTransition(new EventTransition(QEvent::User, historyState)); |
|
890 |
|
891 machine.start(); |
|
892 QCoreApplication::processEvents(); |
|
893 |
|
894 machine.postEvent(new QEvent(QEvent::User)); |
|
895 QCoreApplication::processEvents(); |
|
896 |
|
897 QCOMPARE(machine.isRunning(), true); |
|
898 QCOMPARE(machine.configuration().count(), 1); |
|
899 QVERIFY(machine.configuration().contains(machine.errorState())); |
|
900 QCOMPARE(machine.error(), QStateMachine::NoDefaultStateInHistoryStateError); |
|
901 QCOMPARE(machine.errorString(), QString::fromLatin1("Missing default state in history state 'historyState'")); |
|
902 } |
|
903 |
|
904 void tst_QStateMachine::brokenStateIsNeverEntered() |
|
905 { |
|
906 QStateMachine machine; |
|
907 |
|
908 QObject *entryController = new QObject(&machine); |
|
909 entryController->setProperty("brokenStateEntered", false); |
|
910 entryController->setProperty("childStateEntered", false); |
|
911 entryController->setProperty("errorStateEntered", false); |
|
912 |
|
913 QState *initialState = new QState(&machine); |
|
914 machine.setInitialState(initialState); |
|
915 |
|
916 QState *errorState = new QState(&machine); |
|
917 errorState->assignProperty(entryController, "errorStateEntered", true); |
|
918 machine.setErrorState(errorState); |
|
919 |
|
920 QState *brokenState = new QState(&machine); |
|
921 brokenState->assignProperty(entryController, "brokenStateEntered", true); |
|
922 brokenState->setObjectName("brokenState"); |
|
923 |
|
924 QState *childState = new QState(brokenState); |
|
925 childState->assignProperty(entryController, "childStateEntered", true); |
|
926 |
|
927 initialState->addTransition(new EventTransition(QEvent::User, brokenState)); |
|
928 |
|
929 machine.start(); |
|
930 QCoreApplication::processEvents(); |
|
931 |
|
932 machine.postEvent(new QEvent(QEvent::User)); |
|
933 QCoreApplication::processEvents(); |
|
934 |
|
935 QCOMPARE(entryController->property("errorStateEntered").toBool(), true); |
|
936 QCOMPARE(entryController->property("brokenStateEntered").toBool(), false); |
|
937 QCOMPARE(entryController->property("childStateEntered").toBool(), false); |
|
938 } |
|
939 |
|
940 void tst_QStateMachine::transitionToStateNotInGraph() |
|
941 { |
|
942 QStateMachine machine; |
|
943 |
|
944 QState *initialState = new QState(&machine); |
|
945 initialState->setObjectName("initialState"); |
|
946 machine.setInitialState(initialState); |
|
947 |
|
948 QState independentState; |
|
949 independentState.setObjectName("independentState"); |
|
950 initialState->addTransition(&independentState); |
|
951 |
|
952 machine.start(); |
|
953 QTest::ignoreMessage(QtWarningMsg, "Unrecoverable error detected in running state machine: No common ancestor for targets and source of transition from state 'initialState'"); |
|
954 QCoreApplication::processEvents(); |
|
955 |
|
956 QCOMPARE(machine.isRunning(), false); |
|
957 } |
|
958 |
|
959 void tst_QStateMachine::customErrorStateNotInGraph() |
|
960 { |
|
961 QStateMachine machine; |
|
962 |
|
963 QState errorState; |
|
964 errorState.setObjectName("errorState"); |
|
965 QTest::ignoreMessage(QtWarningMsg, "QState::setErrorState: error state cannot belong to a different state machine"); |
|
966 machine.setErrorState(&errorState); |
|
967 QCOMPARE(machine.errorState(), reinterpret_cast<QAbstractState *>(0)); |
|
968 |
|
969 QState *initialBrokenState = new QState(&machine); |
|
970 initialBrokenState->setObjectName("initialBrokenState"); |
|
971 machine.setInitialState(initialBrokenState); |
|
972 new QState(initialBrokenState); |
|
973 |
|
974 machine.start(); |
|
975 QTest::ignoreMessage(QtWarningMsg, "Unrecoverable error detected in running state machine: Missing initial state in compound state 'initialBrokenState'"); |
|
976 QCoreApplication::processEvents(); |
|
977 |
|
978 QCOMPARE(machine.isRunning(), false); |
|
979 } |
|
980 |
|
981 void tst_QStateMachine::restoreProperties() |
|
982 { |
|
983 QStateMachine machine; |
|
984 QCOMPARE(machine.globalRestorePolicy(), QStateMachine::DoNotRestoreProperties); |
|
985 machine.setGlobalRestorePolicy(QStateMachine::RestoreProperties); |
|
986 |
|
987 QObject *object = new QObject(&machine); |
|
988 object->setProperty("a", 1); |
|
989 object->setProperty("b", 2); |
|
990 |
|
991 QState *S1 = new QState(); |
|
992 S1->setObjectName("S1"); |
|
993 S1->assignProperty(object, "a", 3); |
|
994 machine.addState(S1); |
|
995 |
|
996 QState *S2 = new QState(); |
|
997 S2->setObjectName("S2"); |
|
998 S2->assignProperty(object, "b", 5); |
|
999 machine.addState(S2); |
|
1000 |
|
1001 QState *S3 = new QState(); |
|
1002 S3->setObjectName("S3"); |
|
1003 machine.addState(S3); |
|
1004 |
|
1005 QFinalState *S4 = new QFinalState(); |
|
1006 machine.addState(S4); |
|
1007 |
|
1008 S1->addTransition(new EventTransition(QEvent::User, S2)); |
|
1009 S2->addTransition(new EventTransition(QEvent::User, S3)); |
|
1010 S3->addTransition(S4); |
|
1011 |
|
1012 machine.setInitialState(S1); |
|
1013 machine.start(); |
|
1014 QCoreApplication::processEvents(); |
|
1015 |
|
1016 QCOMPARE(object->property("a").toInt(), 3); |
|
1017 QCOMPARE(object->property("b").toInt(), 2); |
|
1018 |
|
1019 machine.postEvent(new QEvent(QEvent::User)); |
|
1020 QCoreApplication::processEvents(); |
|
1021 |
|
1022 QCOMPARE(object->property("a").toInt(), 1); |
|
1023 QCOMPARE(object->property("b").toInt(), 5); |
|
1024 |
|
1025 machine.postEvent(new QEvent(QEvent::User)); |
|
1026 QCoreApplication::processEvents(); |
|
1027 |
|
1028 QCOMPARE(object->property("a").toInt(), 1); |
|
1029 QCOMPARE(object->property("b").toInt(), 2); |
|
1030 } |
|
1031 |
|
1032 void tst_QStateMachine::rootState() |
|
1033 { |
|
1034 QStateMachine machine; |
|
1035 QCOMPARE(qobject_cast<QState*>(machine.parentState()), (QState*)0); |
|
1036 QCOMPARE(machine.machine(), (QStateMachine*)0); |
|
1037 |
|
1038 QState *s1 = new QState(&machine); |
|
1039 QCOMPARE(s1->parentState(), static_cast<QState*>(&machine)); |
|
1040 |
|
1041 QState *s2 = new QState(); |
|
1042 s2->setParent(&machine); |
|
1043 QCOMPARE(s2->parentState(), static_cast<QState*>(&machine)); |
|
1044 } |
|
1045 |
|
1046 void tst_QStateMachine::addAndRemoveState() |
|
1047 { |
|
1048 #ifdef QT_BUILD_INTERNAL |
|
1049 QStateMachine machine; |
|
1050 QStatePrivate *root_d = QStatePrivate::get(&machine); |
|
1051 QCOMPARE(root_d->childStates().size(), 0); |
|
1052 |
|
1053 QTest::ignoreMessage(QtWarningMsg, "QStateMachine::addState: cannot add null state"); |
|
1054 machine.addState(0); |
|
1055 |
|
1056 QState *s1 = new QState(); |
|
1057 QCOMPARE(s1->parentState(), (QState*)0); |
|
1058 QCOMPARE(s1->machine(), (QStateMachine*)0); |
|
1059 machine.addState(s1); |
|
1060 QCOMPARE(s1->machine(), static_cast<QStateMachine*>(&machine)); |
|
1061 QCOMPARE(s1->parentState(), static_cast<QState*>(&machine)); |
|
1062 QCOMPARE(root_d->childStates().size(), 1); |
|
1063 QCOMPARE(root_d->childStates().at(0), (QAbstractState*)s1); |
|
1064 |
|
1065 QTest::ignoreMessage(QtWarningMsg, "QStateMachine::addState: state has already been added to this machine"); |
|
1066 machine.addState(s1); |
|
1067 |
|
1068 QState *s2 = new QState(); |
|
1069 QCOMPARE(s2->parentState(), (QState*)0); |
|
1070 machine.addState(s2); |
|
1071 QCOMPARE(s2->parentState(), static_cast<QState*>(&machine)); |
|
1072 QCOMPARE(root_d->childStates().size(), 2); |
|
1073 QCOMPARE(root_d->childStates().at(0), (QAbstractState*)s1); |
|
1074 QCOMPARE(root_d->childStates().at(1), (QAbstractState*)s2); |
|
1075 |
|
1076 QTest::ignoreMessage(QtWarningMsg, "QStateMachine::addState: state has already been added to this machine"); |
|
1077 machine.addState(s2); |
|
1078 |
|
1079 machine.removeState(s1); |
|
1080 QCOMPARE(s1->parentState(), (QState*)0); |
|
1081 QCOMPARE(root_d->childStates().size(), 1); |
|
1082 QCOMPARE(root_d->childStates().at(0), (QAbstractState*)s2); |
|
1083 |
|
1084 machine.removeState(s2); |
|
1085 QCOMPARE(s2->parentState(), (QState*)0); |
|
1086 QCOMPARE(root_d->childStates().size(), 0); |
|
1087 |
|
1088 QTest::ignoreMessage(QtWarningMsg, "QStateMachine::removeState: cannot remove null state"); |
|
1089 machine.removeState(0); |
|
1090 |
|
1091 { |
|
1092 QStateMachine machine2; |
|
1093 { |
|
1094 QString warning; |
|
1095 warning.sprintf("QStateMachine::removeState: state %p's machine (%p) is different from this machine (%p)", |
|
1096 &machine2, (void*)0, &machine); |
|
1097 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning)); |
|
1098 machine.removeState(&machine2); |
|
1099 } |
|
1100 // ### check this behavior |
|
1101 machine.addState(&machine2); |
|
1102 QCOMPARE(machine2.parent(), (QObject*)&machine); |
|
1103 } |
|
1104 |
|
1105 delete s1; |
|
1106 delete s2; |
|
1107 // ### how to deal with this? |
|
1108 // machine.removeState(machine.errorState()); |
|
1109 #endif |
|
1110 } |
|
1111 |
|
1112 void tst_QStateMachine::stateEntryAndExit() |
|
1113 { |
|
1114 // Two top-level states |
|
1115 { |
|
1116 QStateMachine machine; |
|
1117 |
|
1118 TestState *s1 = new TestState(&machine); |
|
1119 QTest::ignoreMessage(QtWarningMsg, "QState::addTransition: cannot add transition to null state"); |
|
1120 s1->addTransition((QAbstractState*)0); |
|
1121 QTest::ignoreMessage(QtWarningMsg, "QState::addTransition: cannot add null transition"); |
|
1122 s1->addTransition((QAbstractTransition*)0); |
|
1123 QTest::ignoreMessage(QtWarningMsg, "QState::removeTransition: cannot remove null transition"); |
|
1124 s1->removeTransition((QAbstractTransition*)0); |
|
1125 |
|
1126 TestState *s2 = new TestState(&machine); |
|
1127 QFinalState *s3 = new QFinalState(&machine); |
|
1128 |
|
1129 TestTransition *t = new TestTransition(s2); |
|
1130 QCOMPARE(t->machine(), (QStateMachine*)0); |
|
1131 QCOMPARE(t->sourceState(), (QState*)0); |
|
1132 QCOMPARE(t->targetState(), (QAbstractState*)s2); |
|
1133 QCOMPARE(t->targetStates().size(), 1); |
|
1134 QCOMPARE(t->targetStates().at(0), (QAbstractState*)s2); |
|
1135 t->setTargetState(0); |
|
1136 QCOMPARE(t->targetState(), (QAbstractState*)0); |
|
1137 QVERIFY(t->targetStates().isEmpty()); |
|
1138 t->setTargetState(s2); |
|
1139 QCOMPARE(t->targetState(), (QAbstractState*)s2); |
|
1140 QTest::ignoreMessage(QtWarningMsg, "QAbstractTransition::setTargetStates: target state(s) cannot be null"); |
|
1141 t->setTargetStates(QList<QAbstractState*>() << 0); |
|
1142 QCOMPARE(t->targetState(), (QAbstractState*)s2); |
|
1143 t->setTargetStates(QList<QAbstractState*>() << s2); |
|
1144 QCOMPARE(t->targetState(), (QAbstractState*)s2); |
|
1145 QCOMPARE(t->targetStates().size(), 1); |
|
1146 QCOMPARE(t->targetStates().at(0), (QAbstractState*)s2); |
|
1147 QCOMPARE(s1->addTransition(t), (QAbstractTransition*)t); |
|
1148 QCOMPARE(t->sourceState(), (QState*)s1); |
|
1149 QCOMPARE(t->machine(), &machine); |
|
1150 |
|
1151 { |
|
1152 QAbstractTransition *trans = s2->addTransition(s3); |
|
1153 QVERIFY(trans != 0); |
|
1154 QCOMPARE(trans->sourceState(), (QState*)s2); |
|
1155 QCOMPARE(trans->targetState(), (QAbstractState*)s3); |
|
1156 { |
|
1157 QString warning; |
|
1158 warning.sprintf("QState::removeTransition: transition %p's source state (%p) is different from this state (%p)", trans, s2, s1); |
|
1159 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning)); |
|
1160 s1->removeTransition(trans); |
|
1161 } |
|
1162 s2->removeTransition(trans); |
|
1163 QCOMPARE(trans->sourceState(), (QState*)0); |
|
1164 QCOMPARE(trans->targetState(), (QAbstractState*)s3); |
|
1165 QCOMPARE(s2->addTransition(trans), trans); |
|
1166 QCOMPARE(trans->sourceState(), (QState*)s2); |
|
1167 } |
|
1168 |
|
1169 QSignalSpy startedSpy(&machine, SIGNAL(started())); |
|
1170 QSignalSpy stoppedSpy(&machine, SIGNAL(stopped())); |
|
1171 QSignalSpy finishedSpy(&machine, SIGNAL(finished())); |
|
1172 machine.setInitialState(s1); |
|
1173 QCOMPARE(machine.initialState(), (QAbstractState*)s1); |
|
1174 { |
|
1175 QString warning; |
|
1176 warning.sprintf("QState::setInitialState: state %p is not a child of this state (%p)", &machine, &machine); |
|
1177 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning)); |
|
1178 machine.setInitialState(&machine); |
|
1179 QCOMPARE(machine.initialState(), (QAbstractState*)s1); |
|
1180 } |
|
1181 QVERIFY(machine.configuration().isEmpty()); |
|
1182 globalTick = 0; |
|
1183 QVERIFY(!machine.isRunning()); |
|
1184 QSignalSpy s1EnteredSpy(s1, SIGNAL(entered())); |
|
1185 QSignalSpy s1ExitedSpy(s1, SIGNAL(exited())); |
|
1186 QSignalSpy tTriggeredSpy(t, SIGNAL(triggered())); |
|
1187 QSignalSpy s2EnteredSpy(s2, SIGNAL(entered())); |
|
1188 QSignalSpy s2ExitedSpy(s2, SIGNAL(exited())); |
|
1189 machine.start(); |
|
1190 |
|
1191 QTRY_COMPARE(startedSpy.count(), 1); |
|
1192 QTRY_COMPARE(finishedSpy.count(), 1); |
|
1193 QTRY_COMPARE(stoppedSpy.count(), 0); |
|
1194 QCOMPARE(machine.configuration().count(), 1); |
|
1195 QVERIFY(machine.configuration().contains(s3)); |
|
1196 |
|
1197 // s1 is entered |
|
1198 QCOMPARE(s1->events.count(), 2); |
|
1199 QCOMPARE(s1->events.at(0).first, 0); |
|
1200 QCOMPARE(s1->events.at(0).second, TestState::Entry); |
|
1201 // s1 is exited |
|
1202 QCOMPARE(s1->events.at(1).first, 1); |
|
1203 QCOMPARE(s1->events.at(1).second, TestState::Exit); |
|
1204 // t is triggered |
|
1205 QCOMPARE(t->triggers.count(), 1); |
|
1206 QCOMPARE(t->triggers.at(0), 2); |
|
1207 // s2 is entered |
|
1208 QCOMPARE(s2->events.count(), 2); |
|
1209 QCOMPARE(s2->events.at(0).first, 3); |
|
1210 QCOMPARE(s2->events.at(0).second, TestState::Entry); |
|
1211 // s2 is exited |
|
1212 QCOMPARE(s2->events.at(1).first, 4); |
|
1213 QCOMPARE(s2->events.at(1).second, TestState::Exit); |
|
1214 |
|
1215 QCOMPARE(s1EnteredSpy.count(), 1); |
|
1216 QCOMPARE(s1ExitedSpy.count(), 1); |
|
1217 QCOMPARE(tTriggeredSpy.count(), 1); |
|
1218 QCOMPARE(s2EnteredSpy.count(), 1); |
|
1219 QCOMPARE(s2ExitedSpy.count(), 1); |
|
1220 } |
|
1221 // Two top-level states, one has two child states |
|
1222 { |
|
1223 QStateMachine machine; |
|
1224 |
|
1225 TestState *s1 = new TestState(&machine); |
|
1226 TestState *s11 = new TestState(s1); |
|
1227 TestState *s12 = new TestState(s1); |
|
1228 TestState *s2 = new TestState(&machine); |
|
1229 QFinalState *s3 = new QFinalState(&machine); |
|
1230 s1->setInitialState(s11); |
|
1231 TestTransition *t1 = new TestTransition(s12); |
|
1232 s11->addTransition(t1); |
|
1233 TestTransition *t2 = new TestTransition(s2); |
|
1234 s12->addTransition(t2); |
|
1235 s2->addTransition(s3); |
|
1236 |
|
1237 QSignalSpy startedSpy(&machine, SIGNAL(started())); |
|
1238 QSignalSpy finishedSpy(&machine, SIGNAL(finished())); |
|
1239 machine.setInitialState(s1); |
|
1240 globalTick = 0; |
|
1241 machine.start(); |
|
1242 |
|
1243 QTRY_COMPARE(startedSpy.count(), 1); |
|
1244 QTRY_COMPARE(finishedSpy.count(), 1); |
|
1245 QCOMPARE(machine.configuration().count(), 1); |
|
1246 QVERIFY(machine.configuration().contains(s3)); |
|
1247 |
|
1248 // s1 is entered |
|
1249 QCOMPARE(s1->events.count(), 2); |
|
1250 QCOMPARE(s1->events.at(0).first, 0); |
|
1251 QCOMPARE(s1->events.at(0).second, TestState::Entry); |
|
1252 // s11 is entered |
|
1253 QCOMPARE(s11->events.count(), 2); |
|
1254 QCOMPARE(s11->events.at(0).first, 1); |
|
1255 QCOMPARE(s11->events.at(0).second, TestState::Entry); |
|
1256 // s11 is exited |
|
1257 QCOMPARE(s11->events.at(1).first, 2); |
|
1258 QCOMPARE(s11->events.at(1).second, TestState::Exit); |
|
1259 // t1 is triggered |
|
1260 QCOMPARE(t1->triggers.count(), 1); |
|
1261 QCOMPARE(t1->triggers.at(0), 3); |
|
1262 // s12 is entered |
|
1263 QCOMPARE(s12->events.count(), 2); |
|
1264 QCOMPARE(s12->events.at(0).first, 4); |
|
1265 QCOMPARE(s12->events.at(0).second, TestState::Entry); |
|
1266 // s12 is exited |
|
1267 QCOMPARE(s12->events.at(1).first, 5); |
|
1268 QCOMPARE(s12->events.at(1).second, TestState::Exit); |
|
1269 // s1 is exited |
|
1270 QCOMPARE(s1->events.at(1).first, 6); |
|
1271 QCOMPARE(s1->events.at(1).second, TestState::Exit); |
|
1272 // t2 is triggered |
|
1273 QCOMPARE(t2->triggers.count(), 1); |
|
1274 QCOMPARE(t2->triggers.at(0), 7); |
|
1275 // s2 is entered |
|
1276 QCOMPARE(s2->events.count(), 2); |
|
1277 QCOMPARE(s2->events.at(0).first, 8); |
|
1278 QCOMPARE(s2->events.at(0).second, TestState::Entry); |
|
1279 // s2 is exited |
|
1280 QCOMPARE(s2->events.at(1).first, 9); |
|
1281 QCOMPARE(s2->events.at(1).second, TestState::Exit); |
|
1282 } |
|
1283 } |
|
1284 |
|
1285 void tst_QStateMachine::assignProperty() |
|
1286 { |
|
1287 QStateMachine machine; |
|
1288 QState *s1 = new QState(&machine); |
|
1289 |
|
1290 QTest::ignoreMessage(QtWarningMsg, "QState::assignProperty: cannot assign property 'foo' of null object"); |
|
1291 s1->assignProperty(0, "foo", QVariant()); |
|
1292 |
|
1293 s1->assignProperty(s1, "objectName", "s1"); |
|
1294 QFinalState *s2 = new QFinalState(&machine); |
|
1295 s1->addTransition(s2); |
|
1296 machine.setInitialState(s1); |
|
1297 machine.start(); |
|
1298 QTRY_COMPARE(s1->objectName(), QString::fromLatin1("s1")); |
|
1299 |
|
1300 s1->assignProperty(s1, "objectName", "foo"); |
|
1301 machine.start(); |
|
1302 QTRY_COMPARE(s1->objectName(), QString::fromLatin1("foo")); |
|
1303 |
|
1304 s1->assignProperty(s1, "noSuchProperty", 123); |
|
1305 machine.start(); |
|
1306 QTRY_COMPARE(s1->dynamicPropertyNames().size(), 1); |
|
1307 QCOMPARE(s1->dynamicPropertyNames().at(0), QByteArray("noSuchProperty")); |
|
1308 QCOMPARE(s1->objectName(), QString::fromLatin1("foo")); |
|
1309 |
|
1310 { |
|
1311 QSignalSpy polishedSpy(s1, SIGNAL(polished())); |
|
1312 machine.start(); |
|
1313 QTRY_COMPARE(polishedSpy.count(), 1); |
|
1314 } |
|
1315 |
|
1316 // nested states |
|
1317 { |
|
1318 QState *s11 = new QState(s1); |
|
1319 QString str = QString::fromLatin1("set by nested state"); |
|
1320 s11->assignProperty(s11, "objectName", str); |
|
1321 s1->setInitialState(s11); |
|
1322 machine.start(); |
|
1323 QTRY_COMPARE(s11->objectName(), str); |
|
1324 } |
|
1325 } |
|
1326 |
|
1327 void tst_QStateMachine::assignPropertyWithAnimation() |
|
1328 { |
|
1329 // Single animation |
|
1330 { |
|
1331 QStateMachine machine; |
|
1332 QVERIFY(machine.animationsEnabled()); |
|
1333 machine.setAnimationsEnabled(false); |
|
1334 QVERIFY(!machine.animationsEnabled()); |
|
1335 machine.setAnimationsEnabled(true); |
|
1336 QVERIFY(machine.animationsEnabled()); |
|
1337 QObject obj; |
|
1338 obj.setProperty("foo", 321); |
|
1339 obj.setProperty("bar", 654); |
|
1340 QState *s1 = new QState(&machine); |
|
1341 s1->assignProperty(&obj, "foo", 123); |
|
1342 QState *s2 = new QState(&machine); |
|
1343 s2->assignProperty(&obj, "foo", 456); |
|
1344 s2->assignProperty(&obj, "bar", 789); |
|
1345 QAbstractTransition *trans = s1->addTransition(s2); |
|
1346 QVERIFY(trans->animations().isEmpty()); |
|
1347 QTest::ignoreMessage(QtWarningMsg, "QAbstractTransition::addAnimation: cannot add null animation"); |
|
1348 trans->addAnimation(0); |
|
1349 QPropertyAnimation anim(&obj, "foo"); |
|
1350 anim.setDuration(250); |
|
1351 trans->addAnimation(&anim); |
|
1352 QCOMPARE(trans->animations().size(), 1); |
|
1353 QCOMPARE(trans->animations().at(0), (QAbstractAnimation*)&anim); |
|
1354 QCOMPARE(anim.parent(), (QObject*)0); |
|
1355 QTest::ignoreMessage(QtWarningMsg, "QAbstractTransition::removeAnimation: cannot remove null animation"); |
|
1356 trans->removeAnimation(0); |
|
1357 trans->removeAnimation(&anim); |
|
1358 QVERIFY(trans->animations().isEmpty()); |
|
1359 trans->addAnimation(&anim); |
|
1360 QCOMPARE(trans->animations().size(), 1); |
|
1361 QCOMPARE(trans->animations().at(0), (QAbstractAnimation*)&anim); |
|
1362 QFinalState *s3 = new QFinalState(&machine); |
|
1363 s2->addTransition(s2, SIGNAL(polished()), s3); |
|
1364 |
|
1365 machine.setInitialState(s1); |
|
1366 QSignalSpy finishedSpy(&machine, SIGNAL(finished())); |
|
1367 machine.start(); |
|
1368 QTRY_COMPARE(finishedSpy.count(), 1); |
|
1369 QCOMPARE(obj.property("foo").toInt(), 456); |
|
1370 QCOMPARE(obj.property("bar").toInt(), 789); |
|
1371 } |
|
1372 // Two animations |
|
1373 { |
|
1374 QStateMachine machine; |
|
1375 QObject obj; |
|
1376 obj.setProperty("foo", 321); |
|
1377 obj.setProperty("bar", 654); |
|
1378 QState *s1 = new QState(&machine); |
|
1379 s1->assignProperty(&obj, "foo", 123); |
|
1380 QState *s2 = new QState(&machine); |
|
1381 s2->assignProperty(&obj, "foo", 456); |
|
1382 s2->assignProperty(&obj, "bar", 789); |
|
1383 QAbstractTransition *trans = s1->addTransition(s2); |
|
1384 QPropertyAnimation anim(&obj, "foo"); |
|
1385 anim.setDuration(150); |
|
1386 trans->addAnimation(&anim); |
|
1387 QPropertyAnimation anim2(&obj, "bar"); |
|
1388 anim2.setDuration(150); |
|
1389 trans->addAnimation(&anim2); |
|
1390 QFinalState *s3 = new QFinalState(&machine); |
|
1391 s2->addTransition(s2, SIGNAL(polished()), s3); |
|
1392 |
|
1393 machine.setInitialState(s1); |
|
1394 QSignalSpy finishedSpy(&machine, SIGNAL(finished())); |
|
1395 machine.start(); |
|
1396 QTRY_COMPARE(finishedSpy.count(), 1); |
|
1397 QCOMPARE(obj.property("foo").toInt(), 456); |
|
1398 QCOMPARE(obj.property("bar").toInt(), 789); |
|
1399 } |
|
1400 // Animation group |
|
1401 { |
|
1402 QStateMachine machine; |
|
1403 QObject obj; |
|
1404 obj.setProperty("foo", 321); |
|
1405 obj.setProperty("bar", 654); |
|
1406 QState *s1 = new QState(&machine); |
|
1407 s1->assignProperty(&obj, "foo", 123); |
|
1408 s1->assignProperty(&obj, "bar", 321); |
|
1409 QState *s2 = new QState(&machine); |
|
1410 s2->assignProperty(&obj, "foo", 456); |
|
1411 s2->assignProperty(&obj, "bar", 654); |
|
1412 s2->assignProperty(&obj, "baz", 789); |
|
1413 QAbstractTransition *trans = s1->addTransition(s2); |
|
1414 QSequentialAnimationGroup group; |
|
1415 group.addAnimation(new QPropertyAnimation(&obj, "foo")); |
|
1416 group.addAnimation(new QPropertyAnimation(&obj, "bar")); |
|
1417 trans->addAnimation(&group); |
|
1418 QFinalState *s3 = new QFinalState(&machine); |
|
1419 s2->addTransition(s2, SIGNAL(polished()), s3); |
|
1420 |
|
1421 machine.setInitialState(s1); |
|
1422 QSignalSpy finishedSpy(&machine, SIGNAL(finished())); |
|
1423 machine.start(); |
|
1424 QTRY_COMPARE(finishedSpy.count(), 1); |
|
1425 QCOMPARE(obj.property("foo").toInt(), 456); |
|
1426 QCOMPARE(obj.property("bar").toInt(), 654); |
|
1427 QCOMPARE(obj.property("baz").toInt(), 789); |
|
1428 } |
|
1429 // Nested states |
|
1430 { |
|
1431 QStateMachine machine; |
|
1432 QObject obj; |
|
1433 obj.setProperty("foo", 321); |
|
1434 obj.setProperty("bar", 654); |
|
1435 QState *s1 = new QState(&machine); |
|
1436 QCOMPARE(s1->childMode(), QState::ExclusiveStates); |
|
1437 s1->setChildMode(QState::ParallelStates); |
|
1438 QCOMPARE(s1->childMode(), QState::ParallelStates); |
|
1439 s1->setChildMode(QState::ExclusiveStates); |
|
1440 QCOMPARE(s1->childMode(), QState::ExclusiveStates); |
|
1441 QCOMPARE(s1->initialState(), (QAbstractState*)0); |
|
1442 s1->setObjectName("s1"); |
|
1443 s1->assignProperty(&obj, "foo", 123); |
|
1444 s1->assignProperty(&obj, "bar", 456); |
|
1445 QState *s2 = new QState(&machine); |
|
1446 s2->setObjectName("s2"); |
|
1447 s2->assignProperty(&obj, "foo", 321); |
|
1448 QState *s21 = new QState(s2); |
|
1449 s21->setObjectName("s21"); |
|
1450 s21->assignProperty(&obj, "bar", 654); |
|
1451 QState *s22 = new QState(s2); |
|
1452 s22->setObjectName("s22"); |
|
1453 s22->assignProperty(&obj, "bar", 789); |
|
1454 s2->setInitialState(s21); |
|
1455 QCOMPARE(s2->initialState(), (QAbstractState*)s21); |
|
1456 |
|
1457 QAbstractTransition *trans = s1->addTransition(s2); |
|
1458 QPropertyAnimation anim(&obj, "foo"); |
|
1459 anim.setDuration(500); |
|
1460 trans->addAnimation(&anim); |
|
1461 QPropertyAnimation anim2(&obj, "bar"); |
|
1462 anim2.setDuration(250); |
|
1463 trans->addAnimation(&anim2); |
|
1464 |
|
1465 s21->addTransition(s21, SIGNAL(polished()), s22); |
|
1466 |
|
1467 QFinalState *s3 = new QFinalState(&machine); |
|
1468 s22->addTransition(s2, SIGNAL(polished()), s3); |
|
1469 |
|
1470 machine.setInitialState(s1); |
|
1471 QSignalSpy finishedSpy(&machine, SIGNAL(finished())); |
|
1472 machine.start(); |
|
1473 QTRY_COMPARE(finishedSpy.count(), 1); |
|
1474 QCOMPARE(obj.property("foo").toInt(), 321); |
|
1475 QCOMPARE(obj.property("bar").toInt(), 789); |
|
1476 } |
|
1477 // Aborted animation |
|
1478 { |
|
1479 QStateMachine machine; |
|
1480 SignalEmitter emitter; |
|
1481 QObject obj; |
|
1482 obj.setProperty("foo", 321); |
|
1483 obj.setProperty("bar", 654); |
|
1484 QState *group = new QState(&machine); |
|
1485 QState *s1 = new QState(group); |
|
1486 group->setInitialState(s1); |
|
1487 s1->assignProperty(&obj, "foo", 123); |
|
1488 QState *s2 = new QState(group); |
|
1489 s2->assignProperty(&obj, "foo", 456); |
|
1490 s2->assignProperty(&obj, "bar", 789); |
|
1491 QAbstractTransition *trans = s1->addTransition(&emitter, SIGNAL(signalWithNoArg()), s2); |
|
1492 QPropertyAnimation anim(&obj, "foo"); |
|
1493 anim.setDuration(8000); |
|
1494 trans->addAnimation(&anim); |
|
1495 QPropertyAnimation anim2(&obj, "bar"); |
|
1496 anim2.setDuration(8000); |
|
1497 trans->addAnimation(&anim2); |
|
1498 QState *s3 = new QState(group); |
|
1499 s3->assignProperty(&obj, "foo", 911); |
|
1500 s2->addTransition(&emitter, SIGNAL(signalWithNoArg()), s3); |
|
1501 |
|
1502 machine.setInitialState(group); |
|
1503 machine.start(); |
|
1504 QTRY_COMPARE(machine.configuration().contains(s1), true); |
|
1505 QSignalSpy polishedSpy(s2, SIGNAL(polished())); |
|
1506 emitter.emitSignalWithNoArg(); |
|
1507 QTRY_COMPARE(machine.configuration().contains(s2), true); |
|
1508 QVERIFY(polishedSpy.isEmpty()); |
|
1509 emitter.emitSignalWithNoArg(); // will cause animations from s1-->s2 to abort |
|
1510 QTRY_COMPARE(machine.configuration().contains(s3), true); |
|
1511 QVERIFY(polishedSpy.isEmpty()); |
|
1512 QCOMPARE(obj.property("foo").toInt(), 911); |
|
1513 QCOMPARE(obj.property("bar").toInt(), 789); |
|
1514 } |
|
1515 } |
|
1516 |
|
1517 struct StringEvent : public QEvent |
|
1518 { |
|
1519 public: |
|
1520 StringEvent(const QString &val) |
|
1521 : QEvent(QEvent::Type(QEvent::User+2)), |
|
1522 value(val) {} |
|
1523 |
|
1524 QString value; |
|
1525 }; |
|
1526 |
|
1527 class StringTransition : public QAbstractTransition |
|
1528 { |
|
1529 public: |
|
1530 StringTransition(const QString &value, QAbstractState *target) |
|
1531 : QAbstractTransition(), m_value(value) |
|
1532 { setTargetState(target); } |
|
1533 |
|
1534 protected: |
|
1535 virtual bool eventTest(QEvent *e) |
|
1536 { |
|
1537 if (e->type() != QEvent::Type(QEvent::User+2)) |
|
1538 return false; |
|
1539 StringEvent *se = static_cast<StringEvent*>(e); |
|
1540 return (m_value == se->value) && (!m_cond.isValid() || (m_cond.indexIn(m_value) != -1)); |
|
1541 } |
|
1542 virtual void onTransition(QEvent *) {} |
|
1543 |
|
1544 private: |
|
1545 QString m_value; |
|
1546 QRegExp m_cond; |
|
1547 }; |
|
1548 |
|
1549 class StringEventPoster : public QState |
|
1550 { |
|
1551 public: |
|
1552 StringEventPoster(const QString &value, QState *parent = 0) |
|
1553 : QState(parent), m_value(value), m_delay(-1) {} |
|
1554 |
|
1555 void setString(const QString &value) |
|
1556 { m_value = value; } |
|
1557 void setDelay(int delay) |
|
1558 { m_delay = delay; } |
|
1559 |
|
1560 protected: |
|
1561 virtual void onEntry(QEvent *) |
|
1562 { |
|
1563 if (m_delay == -1) |
|
1564 machine()->postEvent(new StringEvent(m_value)); |
|
1565 else |
|
1566 machine()->postDelayedEvent(new StringEvent(m_value), m_delay); |
|
1567 } |
|
1568 virtual void onExit(QEvent *) {} |
|
1569 |
|
1570 private: |
|
1571 QString m_value; |
|
1572 int m_delay; |
|
1573 }; |
|
1574 |
|
1575 void tst_QStateMachine::postEvent() |
|
1576 { |
|
1577 for (int x = 0; x < 2; ++x) { |
|
1578 QStateMachine machine; |
|
1579 { |
|
1580 QEvent e(QEvent::None); |
|
1581 QTest::ignoreMessage(QtWarningMsg, "QStateMachine::postEvent: cannot post event when the state machine is not running"); |
|
1582 machine.postEvent(&e); |
|
1583 } |
|
1584 StringEventPoster *s1 = new StringEventPoster("a"); |
|
1585 if (x == 1) |
|
1586 s1->setDelay(100); |
|
1587 QFinalState *s2 = new QFinalState; |
|
1588 s1->addTransition(new StringTransition("a", s2)); |
|
1589 machine.addState(s1); |
|
1590 machine.addState(s2); |
|
1591 machine.setInitialState(s1); |
|
1592 QSignalSpy finishedSpy(&machine, SIGNAL(finished())); |
|
1593 machine.start(); |
|
1594 QTRY_COMPARE(finishedSpy.count(), 1); |
|
1595 QCOMPARE(machine.configuration().size(), 1); |
|
1596 QVERIFY(machine.configuration().contains(s2)); |
|
1597 |
|
1598 s1->setString("b"); |
|
1599 QFinalState *s3 = new QFinalState(); |
|
1600 machine.addState(s3); |
|
1601 s1->addTransition(new StringTransition("b", s3)); |
|
1602 finishedSpy.clear(); |
|
1603 machine.start(); |
|
1604 QTRY_COMPARE(finishedSpy.count(), 1); |
|
1605 QCOMPARE(machine.configuration().size(), 1); |
|
1606 QVERIFY(machine.configuration().contains(s3)); |
|
1607 } |
|
1608 } |
|
1609 |
|
1610 void tst_QStateMachine::cancelDelayedEvent() |
|
1611 { |
|
1612 QStateMachine machine; |
|
1613 QTest::ignoreMessage(QtWarningMsg, "QStateMachine::cancelDelayedEvent: the machine is not running"); |
|
1614 QVERIFY(!machine.cancelDelayedEvent(-1)); |
|
1615 |
|
1616 QState *s1 = new QState(&machine); |
|
1617 QFinalState *s2 = new QFinalState(&machine); |
|
1618 s1->addTransition(new StringTransition("a", s2)); |
|
1619 machine.setInitialState(s1); |
|
1620 |
|
1621 QSignalSpy startedSpy(&machine, SIGNAL(started())); |
|
1622 machine.start(); |
|
1623 QTRY_COMPARE(startedSpy.count(), 1); |
|
1624 QCOMPARE(machine.configuration().size(), 1); |
|
1625 QVERIFY(machine.configuration().contains(s1)); |
|
1626 |
|
1627 int id1 = machine.postDelayedEvent(new StringEvent("c"), 50000); |
|
1628 QVERIFY(id1 != -1); |
|
1629 int id2 = machine.postDelayedEvent(new StringEvent("b"), 25000); |
|
1630 QVERIFY(id2 != -1); |
|
1631 QVERIFY(id2 != id1); |
|
1632 int id3 = machine.postDelayedEvent(new StringEvent("a"), 100); |
|
1633 QVERIFY(id3 != -1); |
|
1634 QVERIFY(id3 != id2); |
|
1635 QVERIFY(machine.cancelDelayedEvent(id1)); |
|
1636 QVERIFY(!machine.cancelDelayedEvent(id1)); |
|
1637 QVERIFY(machine.cancelDelayedEvent(id2)); |
|
1638 QVERIFY(!machine.cancelDelayedEvent(id2)); |
|
1639 |
|
1640 QSignalSpy finishedSpy(&machine, SIGNAL(finished())); |
|
1641 QTRY_COMPARE(finishedSpy.count(), 1); |
|
1642 QCOMPARE(machine.configuration().size(), 1); |
|
1643 QVERIFY(machine.configuration().contains(s2)); |
|
1644 } |
|
1645 |
|
1646 void tst_QStateMachine::postDelayedEventAndStop() |
|
1647 { |
|
1648 QStateMachine machine; |
|
1649 QState *s1 = new QState(&machine); |
|
1650 QFinalState *s2 = new QFinalState(&machine); |
|
1651 s1->addTransition(new StringTransition("a", s2)); |
|
1652 machine.setInitialState(s1); |
|
1653 |
|
1654 QSignalSpy startedSpy(&machine, SIGNAL(started())); |
|
1655 machine.start(); |
|
1656 QTRY_COMPARE(startedSpy.count(), 1); |
|
1657 QCOMPARE(machine.configuration().size(), 1); |
|
1658 QVERIFY(machine.configuration().contains(s1)); |
|
1659 |
|
1660 int id1 = machine.postDelayedEvent(new StringEvent("a"), 0); |
|
1661 QVERIFY(id1 != -1); |
|
1662 QSignalSpy stoppedSpy(&machine, SIGNAL(stopped())); |
|
1663 machine.stop(); |
|
1664 QTRY_COMPARE(stoppedSpy.count(), 1); |
|
1665 QCOMPARE(machine.configuration().size(), 1); |
|
1666 QVERIFY(machine.configuration().contains(s1)); |
|
1667 |
|
1668 machine.start(); |
|
1669 QTRY_COMPARE(startedSpy.count(), 2); |
|
1670 QCOMPARE(machine.configuration().size(), 1); |
|
1671 QVERIFY(machine.configuration().contains(s1)); |
|
1672 |
|
1673 int id2 = machine.postDelayedEvent(new StringEvent("a"), 1000); |
|
1674 QVERIFY(id2 != -1); |
|
1675 machine.stop(); |
|
1676 QTRY_COMPARE(stoppedSpy.count(), 2); |
|
1677 machine.start(); |
|
1678 QTRY_COMPARE(startedSpy.count(), 3); |
|
1679 QTestEventLoop::instance().enterLoop(2); |
|
1680 QCOMPARE(machine.configuration().size(), 1); |
|
1681 QVERIFY(machine.configuration().contains(s1)); |
|
1682 } |
|
1683 |
|
1684 void tst_QStateMachine::stateFinished() |
|
1685 { |
|
1686 QStateMachine machine; |
|
1687 QState *s1 = new QState(&machine); |
|
1688 QState *s1_1 = new QState(s1); |
|
1689 QFinalState *s1_2 = new QFinalState(s1); |
|
1690 s1_1->addTransition(s1_2); |
|
1691 s1->setInitialState(s1_1); |
|
1692 QFinalState *s2 = new QFinalState(&machine); |
|
1693 s1->addTransition(s1, SIGNAL(finished()), s2); |
|
1694 machine.setInitialState(s1); |
|
1695 QSignalSpy finishedSpy(&machine, SIGNAL(finished())); |
|
1696 machine.start(); |
|
1697 QTRY_COMPARE(finishedSpy.count(), 1); |
|
1698 QCOMPARE(machine.configuration().size(), 1); |
|
1699 QVERIFY(machine.configuration().contains(s2)); |
|
1700 } |
|
1701 |
|
1702 void tst_QStateMachine::parallelStates() |
|
1703 { |
|
1704 QStateMachine machine; |
|
1705 |
|
1706 QState *s1 = new QState(QState::ParallelStates); |
|
1707 QCOMPARE(s1->childMode(), QState::ParallelStates); |
|
1708 QState *s1_1 = new QState(s1); |
|
1709 QState *s1_1_1 = new QState(s1_1); |
|
1710 QFinalState *s1_1_f = new QFinalState(s1_1); |
|
1711 s1_1_1->addTransition(s1_1_f); |
|
1712 s1_1->setInitialState(s1_1_1); |
|
1713 QState *s1_2 = new QState(s1); |
|
1714 QState *s1_2_1 = new QState(s1_2); |
|
1715 QFinalState *s1_2_f = new QFinalState(s1_2); |
|
1716 s1_2_1->addTransition(s1_2_f); |
|
1717 s1_2->setInitialState(s1_2_1); |
|
1718 { |
|
1719 QString warning; |
|
1720 warning.sprintf("QState::setInitialState: ignoring attempt to set initial state of parallel state group %p", s1); |
|
1721 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning)); |
|
1722 s1->setInitialState(0); |
|
1723 } |
|
1724 machine.addState(s1); |
|
1725 |
|
1726 QFinalState *s2 = new QFinalState(); |
|
1727 machine.addState(s2); |
|
1728 |
|
1729 s1->addTransition(s1, SIGNAL(finished()), s2); |
|
1730 |
|
1731 machine.setInitialState(s1); |
|
1732 QSignalSpy finishedSpy(&machine, SIGNAL(finished())); |
|
1733 machine.start(); |
|
1734 QTRY_COMPARE(finishedSpy.count(), 1); |
|
1735 QCOMPARE(machine.configuration().size(), 1); |
|
1736 QVERIFY(machine.configuration().contains(s2)); |
|
1737 } |
|
1738 |
|
1739 void tst_QStateMachine::parallelRootState() |
|
1740 { |
|
1741 QStateMachine machine; |
|
1742 QState *root = &machine; |
|
1743 QCOMPARE(root->childMode(), QState::ExclusiveStates); |
|
1744 root->setChildMode(QState::ParallelStates); |
|
1745 QCOMPARE(root->childMode(), QState::ParallelStates); |
|
1746 |
|
1747 QState *s1 = new QState(root); |
|
1748 QFinalState *s1_f = new QFinalState(s1); |
|
1749 s1->setInitialState(s1_f); |
|
1750 QState *s2 = new QState(root); |
|
1751 QFinalState *s2_f = new QFinalState(s2); |
|
1752 s2->setInitialState(s2_f); |
|
1753 |
|
1754 QSignalSpy startedSpy(&machine, SIGNAL(started())); |
|
1755 QTest::ignoreMessage(QtWarningMsg, "QStateMachine::start: No initial state set for machine. Refusing to start."); |
|
1756 machine.start(); |
|
1757 QCoreApplication::processEvents(); |
|
1758 QEXPECT_FAIL("", "parallel root state is not supported (task 256587)", Continue); |
|
1759 QCOMPARE(startedSpy.count(), 1); |
|
1760 } |
|
1761 |
|
1762 void tst_QStateMachine::allSourceToTargetConfigurations() |
|
1763 { |
|
1764 QStateMachine machine; |
|
1765 QState *s0 = new QState(&machine); |
|
1766 s0->setObjectName("s0"); |
|
1767 QState *s1 = new QState(s0); |
|
1768 s1->setObjectName("s1"); |
|
1769 QState *s11 = new QState(s1); |
|
1770 s11->setObjectName("s11"); |
|
1771 QState *s2 = new QState(s0); |
|
1772 s2->setObjectName("s2"); |
|
1773 QState *s21 = new QState(s2); |
|
1774 s21->setObjectName("s21"); |
|
1775 QState *s211 = new QState(s21); |
|
1776 s211->setObjectName("s211"); |
|
1777 QFinalState *f = new QFinalState(&machine); |
|
1778 f->setObjectName("f"); |
|
1779 |
|
1780 s0->setInitialState(s1); |
|
1781 s1->setInitialState(s11); |
|
1782 s2->setInitialState(s21); |
|
1783 s21->setInitialState(s211); |
|
1784 |
|
1785 s11->addTransition(new StringTransition("g", s211)); |
|
1786 s1->addTransition(new StringTransition("a", s1)); |
|
1787 s1->addTransition(new StringTransition("b", s11)); |
|
1788 s1->addTransition(new StringTransition("c", s2)); |
|
1789 s1->addTransition(new StringTransition("d", s0)); |
|
1790 s1->addTransition(new StringTransition("f", s211)); |
|
1791 s211->addTransition(new StringTransition("d", s21)); |
|
1792 s211->addTransition(new StringTransition("g", s0)); |
|
1793 s211->addTransition(new StringTransition("h", f)); |
|
1794 s21->addTransition(new StringTransition("b", s211)); |
|
1795 s2->addTransition(new StringTransition("c", s1)); |
|
1796 s2->addTransition(new StringTransition("f", s11)); |
|
1797 s0->addTransition(new StringTransition("e", s211)); |
|
1798 |
|
1799 QSignalSpy finishedSpy(&machine, SIGNAL(finished())); |
|
1800 machine.setInitialState(s0); |
|
1801 machine.start(); |
|
1802 QCoreApplication::processEvents(); |
|
1803 |
|
1804 machine.postEvent(new StringEvent("a")); |
|
1805 QCoreApplication::processEvents(); |
|
1806 machine.postEvent(new StringEvent("b")); |
|
1807 QCoreApplication::processEvents(); |
|
1808 machine.postEvent(new StringEvent("c")); |
|
1809 QCoreApplication::processEvents(); |
|
1810 machine.postEvent(new StringEvent("d")); |
|
1811 QCoreApplication::processEvents(); |
|
1812 machine.postEvent(new StringEvent("e")); |
|
1813 QCoreApplication::processEvents(); |
|
1814 machine.postEvent(new StringEvent("f")); |
|
1815 QCoreApplication::processEvents(); |
|
1816 machine.postEvent(new StringEvent("g")); |
|
1817 QCoreApplication::processEvents(); |
|
1818 machine.postEvent(new StringEvent("h")); |
|
1819 QCoreApplication::processEvents(); |
|
1820 |
|
1821 QTRY_COMPARE(finishedSpy.count(), 1); |
|
1822 } |
|
1823 |
|
1824 class TestSignalTransition : public QSignalTransition |
|
1825 { |
|
1826 public: |
|
1827 TestSignalTransition(QState *sourceState = 0) |
|
1828 : QSignalTransition(sourceState), m_sender(0) |
|
1829 {} |
|
1830 TestSignalTransition(QObject *sender, const char *signal, |
|
1831 QAbstractState *target) |
|
1832 : QSignalTransition(sender, signal), m_sender(0) |
|
1833 { setTargetState(target); } |
|
1834 QObject *senderReceived() const { |
|
1835 return m_sender; |
|
1836 } |
|
1837 int signalIndexReceived() const { |
|
1838 return m_signalIndex; |
|
1839 } |
|
1840 QVariantList argumentsReceived() const { |
|
1841 return m_args; |
|
1842 } |
|
1843 protected: |
|
1844 bool eventTest(QEvent *e) { |
|
1845 if (!QSignalTransition::eventTest(e)) |
|
1846 return false; |
|
1847 QStateMachine::SignalEvent *se = static_cast<QStateMachine::SignalEvent*>(e); |
|
1848 m_sender = se->sender(); |
|
1849 m_signalIndex = se->signalIndex(); |
|
1850 m_args = se->arguments(); |
|
1851 return true; |
|
1852 } |
|
1853 private: |
|
1854 QObject *m_sender; |
|
1855 int m_signalIndex; |
|
1856 QVariantList m_args; |
|
1857 }; |
|
1858 |
|
1859 void tst_QStateMachine::signalTransitions() |
|
1860 { |
|
1861 { |
|
1862 QStateMachine machine; |
|
1863 QState *s0 = new QState(&machine); |
|
1864 QTest::ignoreMessage(QtWarningMsg, "QState::addTransition: sender cannot be null"); |
|
1865 QCOMPARE(s0->addTransition(0, SIGNAL(noSuchSignal()), 0), (QSignalTransition*)0); |
|
1866 |
|
1867 SignalEmitter emitter; |
|
1868 QTest::ignoreMessage(QtWarningMsg, "QState::addTransition: signal cannot be null"); |
|
1869 QCOMPARE(s0->addTransition(&emitter, 0, 0), (QSignalTransition*)0); |
|
1870 |
|
1871 QTest::ignoreMessage(QtWarningMsg, "QState::addTransition: cannot add transition to null state"); |
|
1872 QCOMPARE(s0->addTransition(&emitter, SIGNAL(signalWithNoArg()), 0), (QSignalTransition*)0); |
|
1873 |
|
1874 QFinalState *s1 = new QFinalState(&machine); |
|
1875 QTest::ignoreMessage(QtWarningMsg, "QState::addTransition: no such signal SignalEmitter::noSuchSignal()"); |
|
1876 QCOMPARE(s0->addTransition(&emitter, SIGNAL(noSuchSignal()), s1), (QSignalTransition*)0); |
|
1877 |
|
1878 QSignalTransition *trans = s0->addTransition(&emitter, SIGNAL(signalWithNoArg()), s1); |
|
1879 QVERIFY(trans != 0); |
|
1880 QCOMPARE(trans->sourceState(), s0); |
|
1881 QCOMPARE(trans->targetState(), (QAbstractState*)s1); |
|
1882 QCOMPARE(trans->senderObject(), (QObject*)&emitter); |
|
1883 QCOMPARE(trans->signal(), QByteArray(SIGNAL(signalWithNoArg()))); |
|
1884 |
|
1885 QSignalSpy finishedSpy(&machine, SIGNAL(finished())); |
|
1886 machine.setInitialState(s0); |
|
1887 machine.start(); |
|
1888 QCoreApplication::processEvents(); |
|
1889 |
|
1890 emitter.emitSignalWithNoArg(); |
|
1891 |
|
1892 QTRY_COMPARE(finishedSpy.count(), 1); |
|
1893 |
|
1894 emitter.emitSignalWithNoArg(); |
|
1895 |
|
1896 trans->setSignal(SIGNAL(signalWithIntArg(int))); |
|
1897 QCOMPARE(trans->signal(), QByteArray(SIGNAL(signalWithIntArg(int)))); |
|
1898 machine.start(); |
|
1899 QCoreApplication::processEvents(); |
|
1900 emitter.emitSignalWithIntArg(123); |
|
1901 QTRY_COMPARE(finishedSpy.count(), 2); |
|
1902 |
|
1903 machine.start(); |
|
1904 QCoreApplication::processEvents(); |
|
1905 trans->setSignal(SIGNAL(signalWithNoArg())); |
|
1906 QCOMPARE(trans->signal(), QByteArray(SIGNAL(signalWithNoArg()))); |
|
1907 emitter.emitSignalWithNoArg(); |
|
1908 QTRY_COMPARE(finishedSpy.count(), 3); |
|
1909 |
|
1910 SignalEmitter emitter2; |
|
1911 machine.start(); |
|
1912 QCoreApplication::processEvents(); |
|
1913 trans->setSenderObject(&emitter2); |
|
1914 emitter2.emitSignalWithNoArg(); |
|
1915 QTRY_COMPARE(finishedSpy.count(), 4); |
|
1916 |
|
1917 machine.start(); |
|
1918 QCoreApplication::processEvents(); |
|
1919 QTest::ignoreMessage(QtWarningMsg, "QSignalTransition: no such signal: SignalEmitter::noSuchSignal()"); |
|
1920 trans->setSignal(SIGNAL(noSuchSignal())); |
|
1921 QCOMPARE(trans->signal(), QByteArray(SIGNAL(noSuchSignal()))); |
|
1922 } |
|
1923 { |
|
1924 QStateMachine machine; |
|
1925 QState *s0 = new QState(&machine); |
|
1926 QFinalState *s1 = new QFinalState(&machine); |
|
1927 SignalEmitter emitter; |
|
1928 QSignalTransition *trans = s0->addTransition(&emitter, "signalWithNoArg()", s1); |
|
1929 QVERIFY(trans != 0); |
|
1930 QCOMPARE(trans->sourceState(), s0); |
|
1931 QCOMPARE(trans->targetState(), (QAbstractState*)s1); |
|
1932 QCOMPARE(trans->senderObject(), (QObject*)&emitter); |
|
1933 QCOMPARE(trans->signal(), QByteArray("signalWithNoArg()")); |
|
1934 |
|
1935 QSignalSpy finishedSpy(&machine, SIGNAL(finished())); |
|
1936 machine.setInitialState(s0); |
|
1937 machine.start(); |
|
1938 QCoreApplication::processEvents(); |
|
1939 |
|
1940 emitter.emitSignalWithNoArg(); |
|
1941 |
|
1942 QTRY_COMPARE(finishedSpy.count(), 1); |
|
1943 |
|
1944 trans->setSignal("signalWithIntArg(int)"); |
|
1945 QCOMPARE(trans->signal(), QByteArray("signalWithIntArg(int)")); |
|
1946 machine.start(); |
|
1947 QCoreApplication::processEvents(); |
|
1948 emitter.emitSignalWithIntArg(123); |
|
1949 QTRY_COMPARE(finishedSpy.count(), 2); |
|
1950 } |
|
1951 { |
|
1952 QStateMachine machine; |
|
1953 QState *s0 = new QState(&machine); |
|
1954 QFinalState *s1 = new QFinalState(&machine); |
|
1955 SignalEmitter emitter; |
|
1956 TestSignalTransition *trans = new TestSignalTransition(&emitter, SIGNAL(signalWithIntArg(int)), s1); |
|
1957 s0->addTransition(trans); |
|
1958 |
|
1959 QSignalSpy finishedSpy(&machine, SIGNAL(finished())); |
|
1960 machine.setInitialState(s0); |
|
1961 machine.start(); |
|
1962 QCoreApplication::processEvents(); |
|
1963 |
|
1964 emitter.emitSignalWithIntArg(123); |
|
1965 |
|
1966 QTRY_COMPARE(finishedSpy.count(), 1); |
|
1967 QCOMPARE(trans->senderReceived(), (QObject*)&emitter); |
|
1968 QCOMPARE(trans->signalIndexReceived(), emitter.metaObject()->indexOfSignal("signalWithIntArg(int)")); |
|
1969 QCOMPARE(trans->argumentsReceived().size(), 1); |
|
1970 QCOMPARE(trans->argumentsReceived().at(0).toInt(), 123); |
|
1971 } |
|
1972 { |
|
1973 QStateMachine machine; |
|
1974 QState *s0 = new QState(&machine); |
|
1975 QFinalState *s1 = new QFinalState(&machine); |
|
1976 SignalEmitter emitter; |
|
1977 TestSignalTransition *trans = new TestSignalTransition(&emitter, SIGNAL(signalWithStringArg(QString)), s1); |
|
1978 s0->addTransition(trans); |
|
1979 |
|
1980 QSignalSpy finishedSpy(&machine, SIGNAL(finished())); |
|
1981 machine.setInitialState(s0); |
|
1982 machine.start(); |
|
1983 QCoreApplication::processEvents(); |
|
1984 |
|
1985 QString testString = QString::fromLatin1("hello"); |
|
1986 emitter.emitSignalWithStringArg(testString); |
|
1987 |
|
1988 QTRY_COMPARE(finishedSpy.count(), 1); |
|
1989 QCOMPARE(trans->senderReceived(), (QObject*)&emitter); |
|
1990 QCOMPARE(trans->signalIndexReceived(), emitter.metaObject()->indexOfSignal("signalWithStringArg(QString)")); |
|
1991 QCOMPARE(trans->argumentsReceived().size(), 1); |
|
1992 QCOMPARE(trans->argumentsReceived().at(0).toString(), testString); |
|
1993 } |
|
1994 { |
|
1995 QStateMachine machine; |
|
1996 QState *s0 = new QState(&machine); |
|
1997 QFinalState *s1 = new QFinalState(&machine); |
|
1998 |
|
1999 TestSignalTransition *trans = new TestSignalTransition(); |
|
2000 QCOMPARE(trans->senderObject(), (QObject*)0); |
|
2001 QCOMPARE(trans->signal(), QByteArray()); |
|
2002 |
|
2003 SignalEmitter emitter; |
|
2004 trans->setSenderObject(&emitter); |
|
2005 QCOMPARE(trans->senderObject(), (QObject*)&emitter); |
|
2006 trans->setSignal(SIGNAL(signalWithNoArg())); |
|
2007 QCOMPARE(trans->signal(), QByteArray(SIGNAL(signalWithNoArg()))); |
|
2008 trans->setTargetState(s1); |
|
2009 s0->addTransition(trans); |
|
2010 |
|
2011 QSignalSpy finishedSpy(&machine, SIGNAL(finished())); |
|
2012 machine.setInitialState(s0); |
|
2013 machine.start(); |
|
2014 QCoreApplication::processEvents(); |
|
2015 |
|
2016 emitter.emitSignalWithNoArg(); |
|
2017 |
|
2018 QTRY_COMPARE(finishedSpy.count(), 1); |
|
2019 } |
|
2020 // Multiple transitions for same (object,signal) |
|
2021 { |
|
2022 QStateMachine machine; |
|
2023 SignalEmitter emitter; |
|
2024 QState *s0 = new QState(&machine); |
|
2025 QState *s1 = new QState(&machine); |
|
2026 QSignalTransition *t0 = s0->addTransition(&emitter, SIGNAL(signalWithNoArg()), s1); |
|
2027 QSignalTransition *t1 = s1->addTransition(&emitter, SIGNAL(signalWithNoArg()), s0); |
|
2028 |
|
2029 QSignalSpy finishedSpy(&machine, SIGNAL(finished())); |
|
2030 machine.setInitialState(s0); |
|
2031 machine.start(); |
|
2032 QCoreApplication::processEvents(); |
|
2033 QCOMPARE(machine.configuration().size(), 1); |
|
2034 QVERIFY(machine.configuration().contains(s0)); |
|
2035 |
|
2036 emitter.emitSignalWithNoArg(); |
|
2037 QCoreApplication::processEvents(); |
|
2038 QCOMPARE(machine.configuration().size(), 1); |
|
2039 QVERIFY(machine.configuration().contains(s1)); |
|
2040 |
|
2041 s0->removeTransition(t0); |
|
2042 emitter.emitSignalWithNoArg(); |
|
2043 QCoreApplication::processEvents(); |
|
2044 QCOMPARE(machine.configuration().size(), 1); |
|
2045 QVERIFY(machine.configuration().contains(s0)); |
|
2046 |
|
2047 emitter.emitSignalWithNoArg(); |
|
2048 QCoreApplication::processEvents(); |
|
2049 QCOMPARE(machine.configuration().size(), 1); |
|
2050 QVERIFY(machine.configuration().contains(s0)); |
|
2051 |
|
2052 s1->removeTransition(t1); |
|
2053 emitter.emitSignalWithNoArg(); |
|
2054 QCoreApplication::processEvents(); |
|
2055 QCOMPARE(machine.configuration().size(), 1); |
|
2056 QVERIFY(machine.configuration().contains(s0)); |
|
2057 |
|
2058 s0->addTransition(t0); |
|
2059 s1->addTransition(t1); |
|
2060 emitter.emitSignalWithNoArg(); |
|
2061 QCoreApplication::processEvents(); |
|
2062 QCOMPARE(machine.configuration().size(), 1); |
|
2063 QVERIFY(machine.configuration().contains(s1)); |
|
2064 } |
|
2065 // multiple signal transitions from same source |
|
2066 { |
|
2067 QStateMachine machine; |
|
2068 SignalEmitter emitter; |
|
2069 QState *s0 = new QState(&machine); |
|
2070 QFinalState *s1 = new QFinalState(&machine); |
|
2071 s0->addTransition(&emitter, SIGNAL(signalWithNoArg()), s1); |
|
2072 QFinalState *s2 = new QFinalState(&machine); |
|
2073 s0->addTransition(&emitter, SIGNAL(signalWithIntArg(int)), s2); |
|
2074 QFinalState *s3 = new QFinalState(&machine); |
|
2075 s0->addTransition(&emitter, SIGNAL(signalWithStringArg(QString)), s3); |
|
2076 |
|
2077 QSignalSpy startedSpy(&machine, SIGNAL(started())); |
|
2078 QSignalSpy finishedSpy(&machine, SIGNAL(finished())); |
|
2079 machine.setInitialState(s0); |
|
2080 |
|
2081 machine.start(); |
|
2082 QTRY_COMPARE(startedSpy.count(), 1); |
|
2083 emitter.emitSignalWithNoArg(); |
|
2084 QTRY_COMPARE(finishedSpy.count(), 1); |
|
2085 QCOMPARE(machine.configuration().size(), 1); |
|
2086 QVERIFY(machine.configuration().contains(s1)); |
|
2087 |
|
2088 machine.start(); |
|
2089 QTRY_COMPARE(startedSpy.count(), 2); |
|
2090 emitter.emitSignalWithIntArg(123); |
|
2091 QTRY_COMPARE(finishedSpy.count(), 2); |
|
2092 QCOMPARE(machine.configuration().size(), 1); |
|
2093 QVERIFY(machine.configuration().contains(s2)); |
|
2094 |
|
2095 machine.start(); |
|
2096 QTRY_COMPARE(startedSpy.count(), 3); |
|
2097 emitter.emitSignalWithStringArg("hello"); |
|
2098 QTRY_COMPARE(finishedSpy.count(), 3); |
|
2099 QCOMPARE(machine.configuration().size(), 1); |
|
2100 QVERIFY(machine.configuration().contains(s3)); |
|
2101 } |
|
2102 // signature normalization |
|
2103 { |
|
2104 QStateMachine machine; |
|
2105 SignalEmitter emitter; |
|
2106 QState *s0 = new QState(&machine); |
|
2107 QFinalState *s1 = new QFinalState(&machine); |
|
2108 QSignalTransition *t0 = s0->addTransition(&emitter, SIGNAL( signalWithNoArg( ) ), s1); |
|
2109 QVERIFY(t0 != 0); |
|
2110 QCOMPARE(t0->signal(), QByteArray(SIGNAL( signalWithNoArg( ) ))); |
|
2111 |
|
2112 QSignalTransition *t1 = s0->addTransition(&emitter, SIGNAL( signalWithStringArg( const QString & ) ), s1); |
|
2113 QVERIFY(t1 != 0); |
|
2114 QCOMPARE(t1->signal(), QByteArray(SIGNAL( signalWithStringArg( const QString & ) ))); |
|
2115 |
|
2116 QSignalSpy startedSpy(&machine, SIGNAL(started())); |
|
2117 QSignalSpy finishedSpy(&machine, SIGNAL(finished())); |
|
2118 machine.setInitialState(s0); |
|
2119 machine.start(); |
|
2120 QTRY_COMPARE(startedSpy.count(), 1); |
|
2121 QCOMPARE(finishedSpy.count(), 0); |
|
2122 |
|
2123 emitter.emitSignalWithNoArg(); |
|
2124 |
|
2125 QTRY_COMPARE(finishedSpy.count(), 1); |
|
2126 } |
|
2127 } |
|
2128 |
|
2129 class TestEventTransition : public QEventTransition |
|
2130 { |
|
2131 public: |
|
2132 TestEventTransition(QState *sourceState = 0) |
|
2133 : QEventTransition(sourceState), |
|
2134 m_eventSource(0), m_eventType(QEvent::None) |
|
2135 {} |
|
2136 TestEventTransition(QObject *object, QEvent::Type type, |
|
2137 QAbstractState *target) |
|
2138 : QEventTransition(object, type), |
|
2139 m_eventSource(0), m_eventType(QEvent::None) |
|
2140 { setTargetState(target); } |
|
2141 QObject *eventSourceReceived() const { |
|
2142 return m_eventSource; |
|
2143 } |
|
2144 QEvent::Type eventTypeReceived() const { |
|
2145 return m_eventType; |
|
2146 } |
|
2147 protected: |
|
2148 bool eventTest(QEvent *e) { |
|
2149 if (!QEventTransition::eventTest(e)) |
|
2150 return false; |
|
2151 QStateMachine::WrappedEvent *we = static_cast<QStateMachine::WrappedEvent*>(e); |
|
2152 m_eventSource = we->object(); |
|
2153 m_eventType = we->event()->type(); |
|
2154 return true; |
|
2155 } |
|
2156 private: |
|
2157 QObject *m_eventSource; |
|
2158 QEvent::Type m_eventType; |
|
2159 }; |
|
2160 |
|
2161 void tst_QStateMachine::eventTransitions() |
|
2162 { |
|
2163 QPushButton button; |
|
2164 { |
|
2165 QStateMachine machine; |
|
2166 QState *s0 = new QState(&machine); |
|
2167 QFinalState *s1 = new QFinalState(&machine); |
|
2168 |
|
2169 QMouseEventTransition *trans; |
|
2170 trans = new QMouseEventTransition(&button, QEvent::MouseButtonPress, Qt::LeftButton); |
|
2171 QCOMPARE(trans->targetState(), (QAbstractState*)0); |
|
2172 trans->setTargetState(s1); |
|
2173 QCOMPARE(trans->eventType(), QEvent::MouseButtonPress); |
|
2174 QCOMPARE(trans->button(), Qt::LeftButton); |
|
2175 QCOMPARE(trans->targetState(), (QAbstractState*)s1); |
|
2176 s0->addTransition(trans); |
|
2177 |
|
2178 QSignalSpy finishedSpy(&machine, SIGNAL(finished())); |
|
2179 machine.setInitialState(s0); |
|
2180 machine.start(); |
|
2181 QCoreApplication::processEvents(); |
|
2182 |
|
2183 QTest::mousePress(&button, Qt::LeftButton); |
|
2184 QTRY_COMPARE(finishedSpy.count(), 1); |
|
2185 |
|
2186 QTest::mousePress(&button, Qt::LeftButton); |
|
2187 |
|
2188 trans->setEventType(QEvent::MouseButtonRelease); |
|
2189 QCOMPARE(trans->eventType(), QEvent::MouseButtonRelease); |
|
2190 machine.start(); |
|
2191 QCoreApplication::processEvents(); |
|
2192 QTest::mouseRelease(&button, Qt::LeftButton); |
|
2193 QTRY_COMPARE(finishedSpy.count(), 2); |
|
2194 |
|
2195 machine.start(); |
|
2196 QCoreApplication::processEvents(); |
|
2197 trans->setEventType(QEvent::MouseButtonPress); |
|
2198 QTest::mousePress(&button, Qt::LeftButton); |
|
2199 QTRY_COMPARE(finishedSpy.count(), 3); |
|
2200 |
|
2201 QPushButton button2; |
|
2202 machine.start(); |
|
2203 QCoreApplication::processEvents(); |
|
2204 trans->setEventSource(&button2); |
|
2205 QTest::mousePress(&button2, Qt::LeftButton); |
|
2206 QTRY_COMPARE(finishedSpy.count(), 4); |
|
2207 } |
|
2208 for (int x = 0; x < 2; ++x) { |
|
2209 QStateMachine machine; |
|
2210 QState *s0 = new QState(&machine); |
|
2211 QFinalState *s1 = new QFinalState(&machine); |
|
2212 |
|
2213 QEventTransition *trans; |
|
2214 if (x == 0) { |
|
2215 trans = new QEventTransition(); |
|
2216 QCOMPARE(trans->eventSource(), (QObject*)0); |
|
2217 QCOMPARE(trans->eventType(), QEvent::None); |
|
2218 trans->setEventSource(&button); |
|
2219 trans->setEventType(QEvent::MouseButtonPress); |
|
2220 trans->setTargetState(s1); |
|
2221 } else if (x == 1) { |
|
2222 trans = new QEventTransition(&button, QEvent::MouseButtonPress); |
|
2223 trans->setTargetState(s1); |
|
2224 } |
|
2225 QCOMPARE(trans->eventSource(), (QObject*)&button); |
|
2226 QCOMPARE(trans->eventType(), QEvent::MouseButtonPress); |
|
2227 QCOMPARE(trans->targetState(), (QAbstractState*)s1); |
|
2228 s0->addTransition(trans); |
|
2229 |
|
2230 QSignalSpy finishedSpy(&machine, SIGNAL(finished())); |
|
2231 machine.setInitialState(s0); |
|
2232 machine.start(); |
|
2233 QCoreApplication::processEvents(); |
|
2234 |
|
2235 QTest::mousePress(&button, Qt::LeftButton); |
|
2236 QCoreApplication::processEvents(); |
|
2237 |
|
2238 QTRY_COMPARE(finishedSpy.count(), 1); |
|
2239 } |
|
2240 { |
|
2241 QStateMachine machine; |
|
2242 QState *s0 = new QState(&machine); |
|
2243 QFinalState *s1 = new QFinalState(&machine); |
|
2244 |
|
2245 QMouseEventTransition *trans = new QMouseEventTransition(); |
|
2246 QCOMPARE(trans->eventSource(), (QObject*)0); |
|
2247 QCOMPARE(trans->eventType(), QEvent::None); |
|
2248 QCOMPARE(trans->button(), Qt::NoButton); |
|
2249 trans->setEventSource(&button); |
|
2250 trans->setEventType(QEvent::MouseButtonPress); |
|
2251 trans->setButton(Qt::LeftButton); |
|
2252 trans->setTargetState(s1); |
|
2253 s0->addTransition(trans); |
|
2254 |
|
2255 QSignalSpy finishedSpy(&machine, SIGNAL(finished())); |
|
2256 machine.setInitialState(s0); |
|
2257 machine.start(); |
|
2258 QCoreApplication::processEvents(); |
|
2259 |
|
2260 QTest::mousePress(&button, Qt::LeftButton); |
|
2261 QCoreApplication::processEvents(); |
|
2262 |
|
2263 QTRY_COMPARE(finishedSpy.count(), 1); |
|
2264 } |
|
2265 |
|
2266 { |
|
2267 QStateMachine machine; |
|
2268 QState *s0 = new QState(&machine); |
|
2269 QFinalState *s1 = new QFinalState(&machine); |
|
2270 |
|
2271 QKeyEventTransition *trans = new QKeyEventTransition(&button, QEvent::KeyPress, Qt::Key_A); |
|
2272 QCOMPARE(trans->eventType(), QEvent::KeyPress); |
|
2273 QCOMPARE(trans->key(), (int)Qt::Key_A); |
|
2274 trans->setTargetState(s1); |
|
2275 s0->addTransition(trans); |
|
2276 |
|
2277 QSignalSpy finishedSpy(&machine, SIGNAL(finished())); |
|
2278 machine.setInitialState(s0); |
|
2279 machine.start(); |
|
2280 QCoreApplication::processEvents(); |
|
2281 |
|
2282 QTest::keyPress(&button, Qt::Key_A); |
|
2283 QCoreApplication::processEvents(); |
|
2284 |
|
2285 QTRY_COMPARE(finishedSpy.count(), 1); |
|
2286 } |
|
2287 { |
|
2288 QStateMachine machine; |
|
2289 QState *s0 = new QState(&machine); |
|
2290 QFinalState *s1 = new QFinalState(&machine); |
|
2291 |
|
2292 QKeyEventTransition *trans = new QKeyEventTransition(); |
|
2293 QCOMPARE(trans->eventSource(), (QObject*)0); |
|
2294 QCOMPARE(trans->eventType(), QEvent::None); |
|
2295 QCOMPARE(trans->key(), 0); |
|
2296 trans->setEventSource(&button); |
|
2297 trans->setEventType(QEvent::KeyPress); |
|
2298 trans->setKey(Qt::Key_A); |
|
2299 trans->setTargetState(s1); |
|
2300 s0->addTransition(trans); |
|
2301 |
|
2302 QSignalSpy finishedSpy(&machine, SIGNAL(finished())); |
|
2303 machine.setInitialState(s0); |
|
2304 machine.start(); |
|
2305 QCoreApplication::processEvents(); |
|
2306 |
|
2307 QTest::keyPress(&button, Qt::Key_A); |
|
2308 QCoreApplication::processEvents(); |
|
2309 |
|
2310 QTRY_COMPARE(finishedSpy.count(), 1); |
|
2311 } |
|
2312 // Multiple transitions for same (object,event) |
|
2313 { |
|
2314 QStateMachine machine; |
|
2315 QState *s0 = new QState(&machine); |
|
2316 QState *s1 = new QState(&machine); |
|
2317 QEventTransition *t0 = new QEventTransition(&button, QEvent::MouseButtonPress); |
|
2318 t0->setTargetState(s1); |
|
2319 s0->addTransition(t0); |
|
2320 QEventTransition *t1 = new QEventTransition(&button, QEvent::MouseButtonPress); |
|
2321 t1->setTargetState(s0); |
|
2322 s1->addTransition(t1); |
|
2323 |
|
2324 QSignalSpy finishedSpy(&machine, SIGNAL(finished())); |
|
2325 machine.setInitialState(s0); |
|
2326 machine.start(); |
|
2327 QCoreApplication::processEvents(); |
|
2328 QCOMPARE(machine.configuration().size(), 1); |
|
2329 QVERIFY(machine.configuration().contains(s0)); |
|
2330 |
|
2331 QTest::mousePress(&button, Qt::LeftButton); |
|
2332 QCoreApplication::processEvents(); |
|
2333 QCOMPARE(machine.configuration().size(), 1); |
|
2334 QVERIFY(machine.configuration().contains(s1)); |
|
2335 |
|
2336 s0->removeTransition(t0); |
|
2337 QTest::mousePress(&button, Qt::LeftButton); |
|
2338 QCoreApplication::processEvents(); |
|
2339 QCOMPARE(machine.configuration().size(), 1); |
|
2340 QVERIFY(machine.configuration().contains(s0)); |
|
2341 |
|
2342 QTest::mousePress(&button, Qt::LeftButton); |
|
2343 QCoreApplication::processEvents(); |
|
2344 QCOMPARE(machine.configuration().size(), 1); |
|
2345 QVERIFY(machine.configuration().contains(s0)); |
|
2346 |
|
2347 s1->removeTransition(t1); |
|
2348 QTest::mousePress(&button, Qt::LeftButton); |
|
2349 QCoreApplication::processEvents(); |
|
2350 QCOMPARE(machine.configuration().size(), 1); |
|
2351 QVERIFY(machine.configuration().contains(s0)); |
|
2352 |
|
2353 s0->addTransition(t0); |
|
2354 s1->addTransition(t1); |
|
2355 QTest::mousePress(&button, Qt::LeftButton); |
|
2356 QCoreApplication::processEvents(); |
|
2357 QCOMPARE(machine.configuration().size(), 1); |
|
2358 QVERIFY(machine.configuration().contains(s1)); |
|
2359 } |
|
2360 // multiple event transitions from same source |
|
2361 { |
|
2362 QStateMachine machine; |
|
2363 QState *s0 = new QState(&machine); |
|
2364 QFinalState *s1 = new QFinalState(&machine); |
|
2365 QFinalState *s2 = new QFinalState(&machine); |
|
2366 QEventTransition *t0 = new QEventTransition(&button, QEvent::MouseButtonPress); |
|
2367 t0->setTargetState(s1); |
|
2368 s0->addTransition(t0); |
|
2369 QEventTransition *t1 = new QEventTransition(&button, QEvent::MouseButtonRelease); |
|
2370 t1->setTargetState(s2); |
|
2371 s0->addTransition(t1); |
|
2372 |
|
2373 QSignalSpy startedSpy(&machine, SIGNAL(started())); |
|
2374 QSignalSpy finishedSpy(&machine, SIGNAL(finished())); |
|
2375 machine.setInitialState(s0); |
|
2376 |
|
2377 machine.start(); |
|
2378 QTRY_COMPARE(startedSpy.count(), 1); |
|
2379 QTest::mousePress(&button, Qt::LeftButton); |
|
2380 QTRY_COMPARE(finishedSpy.count(), 1); |
|
2381 QCOMPARE(machine.configuration().size(), 1); |
|
2382 QVERIFY(machine.configuration().contains(s1)); |
|
2383 |
|
2384 machine.start(); |
|
2385 QTRY_COMPARE(startedSpy.count(), 2); |
|
2386 QTest::mouseRelease(&button, Qt::LeftButton); |
|
2387 QTRY_COMPARE(finishedSpy.count(), 2); |
|
2388 QCOMPARE(machine.configuration().size(), 1); |
|
2389 QVERIFY(machine.configuration().contains(s2)); |
|
2390 } |
|
2391 // custom event |
|
2392 { |
|
2393 QStateMachine machine; |
|
2394 QState *s0 = new QState(&machine); |
|
2395 QFinalState *s1 = new QFinalState(&machine); |
|
2396 |
|
2397 QEventTransition *trans = new QEventTransition(&button, QEvent::Type(QEvent::User+1)); |
|
2398 trans->setTargetState(s1); |
|
2399 s0->addTransition(trans); |
|
2400 |
|
2401 QSignalSpy startedSpy(&machine, SIGNAL(started())); |
|
2402 machine.setInitialState(s0); |
|
2403 machine.start(); |
|
2404 QTest::ignoreMessage(QtWarningMsg, "QObject event transitions are not supported for custom types"); |
|
2405 QTRY_COMPARE(startedSpy.count(), 1); |
|
2406 } |
|
2407 // custom transition |
|
2408 { |
|
2409 QStateMachine machine; |
|
2410 QState *s0 = new QState(&machine); |
|
2411 QFinalState *s1 = new QFinalState(&machine); |
|
2412 |
|
2413 TestEventTransition *trans = new TestEventTransition(&button, QEvent::MouseButtonPress, s1); |
|
2414 s0->addTransition(trans); |
|
2415 QCOMPARE(trans->eventSourceReceived(), (QObject*)0); |
|
2416 QCOMPARE(trans->eventTypeReceived(), QEvent::None); |
|
2417 |
|
2418 QSignalSpy finishedSpy(&machine, SIGNAL(finished())); |
|
2419 machine.setInitialState(s0); |
|
2420 machine.start(); |
|
2421 QCoreApplication::processEvents(); |
|
2422 |
|
2423 QTest::mousePress(&button, Qt::LeftButton); |
|
2424 QCoreApplication::processEvents(); |
|
2425 |
|
2426 QTRY_COMPARE(finishedSpy.count(), 1); |
|
2427 |
|
2428 QCOMPARE(trans->eventSourceReceived(), (QObject*)&button); |
|
2429 QCOMPARE(trans->eventTypeReceived(), QEvent::MouseButtonPress); |
|
2430 } |
|
2431 } |
|
2432 |
|
2433 void tst_QStateMachine::graphicsSceneEventTransitions() |
|
2434 { |
|
2435 QGraphicsScene scene; |
|
2436 QGraphicsTextItem *textItem = scene.addText("foo"); |
|
2437 |
|
2438 QStateMachine machine; |
|
2439 QState *s1 = new QState(&machine); |
|
2440 QFinalState *s2 = new QFinalState(&machine); |
|
2441 QEventTransition *t = new QEventTransition(textItem, QEvent::GraphicsSceneMouseMove); |
|
2442 t->setTargetState(s2); |
|
2443 s1->addTransition(t); |
|
2444 machine.setInitialState(s1); |
|
2445 |
|
2446 QSignalSpy startedSpy(&machine, SIGNAL(started())); |
|
2447 QSignalSpy finishedSpy(&machine, SIGNAL(finished())); |
|
2448 machine.start(); |
|
2449 QTRY_COMPARE(startedSpy.count(), 1); |
|
2450 QVERIFY(finishedSpy.count() == 0); |
|
2451 QGraphicsSceneMouseEvent mouseEvent(QEvent::GraphicsSceneMouseMove); |
|
2452 scene.sendEvent(textItem, &mouseEvent); |
|
2453 QTRY_COMPARE(finishedSpy.count(), 1); |
|
2454 } |
|
2455 |
|
2456 void tst_QStateMachine::historyStates() |
|
2457 { |
|
2458 for (int x = 0; x < 2; ++x) { |
|
2459 QStateMachine machine; |
|
2460 QState *root = &machine; |
|
2461 QState *s0 = new QState(root); |
|
2462 QState *s00 = new QState(s0); |
|
2463 QState *s01 = new QState(s0); |
|
2464 QHistoryState *s0h; |
|
2465 if (x == 0) { |
|
2466 s0h = new QHistoryState(s0); |
|
2467 QCOMPARE(s0h->historyType(), QHistoryState::ShallowHistory); |
|
2468 s0h->setHistoryType(QHistoryState::DeepHistory); |
|
2469 } else { |
|
2470 s0h = new QHistoryState(QHistoryState::DeepHistory, s0); |
|
2471 } |
|
2472 QCOMPARE(s0h->historyType(), QHistoryState::DeepHistory); |
|
2473 s0h->setHistoryType(QHistoryState::ShallowHistory); |
|
2474 QCOMPARE(s0h->historyType(), QHistoryState::ShallowHistory); |
|
2475 QCOMPARE(s0h->defaultState(), (QAbstractState*)0); |
|
2476 s0h->setDefaultState(s00); |
|
2477 QCOMPARE(s0h->defaultState(), (QAbstractState*)s00); |
|
2478 QString warning; |
|
2479 warning.sprintf("QHistoryState::setDefaultState: state %p does not belong to this history state's group (%p)", s0, s0); |
|
2480 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning)); |
|
2481 s0h->setDefaultState(s0); |
|
2482 QState *s1 = new QState(root); |
|
2483 QFinalState *s2 = new QFinalState(root); |
|
2484 |
|
2485 s00->addTransition(new StringTransition("a", s01)); |
|
2486 s0->addTransition(new StringTransition("b", s1)); |
|
2487 s1->addTransition(new StringTransition("c", s0h)); |
|
2488 s0->addTransition(new StringTransition("d", s2)); |
|
2489 |
|
2490 root->setInitialState(s0); |
|
2491 s0->setInitialState(s00); |
|
2492 |
|
2493 QSignalSpy finishedSpy(&machine, SIGNAL(finished())); |
|
2494 machine.start(); |
|
2495 QCoreApplication::processEvents(); |
|
2496 QCOMPARE(machine.configuration().size(), 2); |
|
2497 QVERIFY(machine.configuration().contains(s0)); |
|
2498 QVERIFY(machine.configuration().contains(s00)); |
|
2499 |
|
2500 machine.postEvent(new StringEvent("a")); |
|
2501 QCoreApplication::processEvents(); |
|
2502 QCOMPARE(machine.configuration().size(), 2); |
|
2503 QVERIFY(machine.configuration().contains(s0)); |
|
2504 QVERIFY(machine.configuration().contains(s01)); |
|
2505 |
|
2506 machine.postEvent(new StringEvent("b")); |
|
2507 QCoreApplication::processEvents(); |
|
2508 QCOMPARE(machine.configuration().size(), 1); |
|
2509 QVERIFY(machine.configuration().contains(s1)); |
|
2510 |
|
2511 machine.postEvent(new StringEvent("c")); |
|
2512 QCoreApplication::processEvents(); |
|
2513 QCOMPARE(machine.configuration().size(), 2); |
|
2514 QVERIFY(machine.configuration().contains(s0)); |
|
2515 QVERIFY(machine.configuration().contains(s01)); |
|
2516 |
|
2517 machine.postEvent(new StringEvent("d")); |
|
2518 QCoreApplication::processEvents(); |
|
2519 QCOMPARE(machine.configuration().size(), 1); |
|
2520 QVERIFY(machine.configuration().contains(s2)); |
|
2521 |
|
2522 QTRY_COMPARE(finishedSpy.count(), 1); |
|
2523 } |
|
2524 } |
|
2525 |
|
2526 void tst_QStateMachine::startAndStop() |
|
2527 { |
|
2528 QStateMachine machine; |
|
2529 QSignalSpy startedSpy(&machine, SIGNAL(started())); |
|
2530 QSignalSpy stoppedSpy(&machine, SIGNAL(stopped())); |
|
2531 QSignalSpy finishedSpy(&machine, SIGNAL(finished())); |
|
2532 QVERIFY(!machine.isRunning()); |
|
2533 QTest::ignoreMessage(QtWarningMsg, "QStateMachine::start: No initial state set for machine. Refusing to start."); |
|
2534 machine.start(); |
|
2535 QCOMPARE(startedSpy.count(), 0); |
|
2536 QCOMPARE(stoppedSpy.count(), 0); |
|
2537 QCOMPARE(finishedSpy.count(), 0); |
|
2538 QVERIFY(!machine.isRunning()); |
|
2539 machine.stop(); |
|
2540 QCOMPARE(startedSpy.count(), 0); |
|
2541 QCOMPARE(stoppedSpy.count(), 0); |
|
2542 QCOMPARE(finishedSpy.count(), 0); |
|
2543 |
|
2544 QState *s1 = new QState(&machine); |
|
2545 machine.setInitialState(s1); |
|
2546 machine.start(); |
|
2547 QTRY_COMPARE(machine.isRunning(), true); |
|
2548 QTRY_COMPARE(startedSpy.count(), 1); |
|
2549 QCOMPARE(stoppedSpy.count(), 0); |
|
2550 QCOMPARE(finishedSpy.count(), 0); |
|
2551 QCOMPARE(machine.configuration().count(), 1); |
|
2552 QVERIFY(machine.configuration().contains(s1)); |
|
2553 |
|
2554 QTest::ignoreMessage(QtWarningMsg, "QStateMachine::start(): already running"); |
|
2555 machine.start(); |
|
2556 |
|
2557 machine.stop(); |
|
2558 QTRY_COMPARE(machine.isRunning(), false); |
|
2559 QTRY_COMPARE(stoppedSpy.count(), 1); |
|
2560 QCOMPARE(startedSpy.count(), 1); |
|
2561 QCOMPARE(finishedSpy.count(), 0); |
|
2562 |
|
2563 QCOMPARE(machine.configuration().count(), 1); |
|
2564 QVERIFY(machine.configuration().contains(s1)); |
|
2565 |
|
2566 machine.start(); |
|
2567 machine.stop(); |
|
2568 QTRY_COMPARE(startedSpy.count(), 2); |
|
2569 QCOMPARE(stoppedSpy.count(), 2); |
|
2570 } |
|
2571 |
|
2572 void tst_QStateMachine::targetStateWithNoParent() |
|
2573 { |
|
2574 QStateMachine machine; |
|
2575 QState *s1 = new QState(&machine); |
|
2576 s1->setObjectName("s1"); |
|
2577 QState s2; |
|
2578 s1->addTransition(&s2); |
|
2579 machine.setInitialState(s1); |
|
2580 QSignalSpy startedSpy(&machine, SIGNAL(started())); |
|
2581 QSignalSpy stoppedSpy(&machine, SIGNAL(stopped())); |
|
2582 QSignalSpy finishedSpy(&machine, SIGNAL(finished())); |
|
2583 machine.start(); |
|
2584 QTest::ignoreMessage(QtWarningMsg, "Unrecoverable error detected in running state machine: No common ancestor for targets and source of transition from state 's1'"); |
|
2585 QTRY_COMPARE(startedSpy.count(), 1); |
|
2586 QCOMPARE(machine.isRunning(), false); |
|
2587 QCOMPARE(stoppedSpy.count(), 1); |
|
2588 QCOMPARE(finishedSpy.count(), 0); |
|
2589 QCOMPARE(machine.error(), QStateMachine::NoCommonAncestorForTransitionError); |
|
2590 } |
|
2591 |
|
2592 void tst_QStateMachine::targetStateDeleted() |
|
2593 { |
|
2594 QStateMachine machine; |
|
2595 QState *s1 = new QState(&machine); |
|
2596 s1->setObjectName("s1"); |
|
2597 QState *s2 = new QState(&machine); |
|
2598 QAbstractTransition *trans = s1->addTransition(s2); |
|
2599 delete s2; |
|
2600 QCOMPARE(trans->targetState(), (QAbstractState*)0); |
|
2601 QVERIFY(trans->targetStates().isEmpty()); |
|
2602 } |
|
2603 |
|
2604 void tst_QStateMachine::defaultGlobalRestorePolicy() |
|
2605 { |
|
2606 QStateMachine machine; |
|
2607 |
|
2608 QObject *propertyHolder = new QObject(&machine); |
|
2609 propertyHolder->setProperty("a", 1); |
|
2610 propertyHolder->setProperty("b", 2); |
|
2611 |
|
2612 QState *s1 = new QState(&machine); |
|
2613 s1->assignProperty(propertyHolder, "a", 3); |
|
2614 |
|
2615 QState *s2 = new QState(&machine); |
|
2616 s2->assignProperty(propertyHolder, "b", 4); |
|
2617 |
|
2618 QState *s3 = new QState(&machine); |
|
2619 |
|
2620 s1->addTransition(new EventTransition(QEvent::User, s2)); |
|
2621 s2->addTransition(new EventTransition(QEvent::User, s3)); |
|
2622 |
|
2623 machine.setInitialState(s1); |
|
2624 machine.start(); |
|
2625 QCoreApplication::processEvents(); |
|
2626 |
|
2627 QCOMPARE(propertyHolder->property("a").toInt(), 3); |
|
2628 QCOMPARE(propertyHolder->property("b").toInt(), 2); |
|
2629 |
|
2630 machine.postEvent(new QEvent(QEvent::User)); |
|
2631 QCoreApplication::processEvents(); |
|
2632 |
|
2633 QCOMPARE(propertyHolder->property("a").toInt(), 3); |
|
2634 QCOMPARE(propertyHolder->property("b").toInt(), 4); |
|
2635 |
|
2636 machine.postEvent(new QEvent(QEvent::User)); |
|
2637 QCoreApplication::processEvents(); |
|
2638 |
|
2639 QCOMPARE(propertyHolder->property("a").toInt(), 3); |
|
2640 QCOMPARE(propertyHolder->property("b").toInt(), 4); |
|
2641 } |
|
2642 |
|
2643 void tst_QStateMachine::noInitialStateForInitialState() |
|
2644 { |
|
2645 QStateMachine machine; |
|
2646 |
|
2647 QState *initialState = new QState(&machine); |
|
2648 initialState->setObjectName("initialState"); |
|
2649 machine.setInitialState(initialState); |
|
2650 |
|
2651 QState *childState = new QState(initialState); |
|
2652 (void)childState; |
|
2653 |
|
2654 QTest::ignoreMessage(QtWarningMsg, "Unrecoverable error detected in running state machine: " |
|
2655 "Missing initial state in compound state 'initialState'"); |
|
2656 machine.start(); |
|
2657 QCoreApplication::processEvents(); |
|
2658 |
|
2659 QCOMPARE(machine.isRunning(), false); |
|
2660 QCOMPARE(int(machine.error()), int(QStateMachine::NoInitialStateError)); |
|
2661 } |
|
2662 |
|
2663 /* |
|
2664 void tst_QStateMachine::restorePolicyNotInherited() |
|
2665 { |
|
2666 QStateMachine machine; |
|
2667 |
|
2668 QObject *propertyHolder = new QObject(); |
|
2669 propertyHolder->setProperty("a", 1); |
|
2670 propertyHolder->setProperty("b", 2); |
|
2671 |
|
2672 QState *parentState = new QState(&machine); |
|
2673 parentState->setObjectName("parentState"); |
|
2674 parentState->setRestorePolicy(QState::RestoreProperties); |
|
2675 |
|
2676 QState *s1 = new QState(parentState); |
|
2677 s1->setObjectName("s1"); |
|
2678 s1->assignProperty(propertyHolder, "a", 3); |
|
2679 parentState->setInitialState(s1); |
|
2680 |
|
2681 QState *s2 = new QState(parentState); |
|
2682 s2->setObjectName("s2"); |
|
2683 s2->assignProperty(propertyHolder, "b", 4); |
|
2684 |
|
2685 QState *s3 = new QState(parentState); |
|
2686 s3->setObjectName("s3"); |
|
2687 |
|
2688 s1->addTransition(new EventTransition(QEvent::User, s2)); |
|
2689 s2->addTransition(new EventTransition(QEvent::User, s3)); |
|
2690 |
|
2691 machine.setInitialState(parentState); |
|
2692 machine.start(); |
|
2693 QCoreApplication::processEvents(); |
|
2694 |
|
2695 QCOMPARE(propertyHolder->property("a").toInt(), 3); |
|
2696 QCOMPARE(propertyHolder->property("b").toInt(), 2); |
|
2697 |
|
2698 machine.postEvent(new QEvent(QEvent::User)); |
|
2699 QCoreApplication::processEvents(); |
|
2700 |
|
2701 QCOMPARE(propertyHolder->property("a").toInt(), 3); |
|
2702 QCOMPARE(propertyHolder->property("b").toInt(), 4); |
|
2703 |
|
2704 machine.postEvent(new QEvent(QEvent::User)); |
|
2705 QCoreApplication::processEvents(); |
|
2706 |
|
2707 QCOMPARE(propertyHolder->property("a").toInt(), 3); |
|
2708 QCOMPARE(propertyHolder->property("b").toInt(), 4); |
|
2709 |
|
2710 }*/ |
|
2711 |
|
2712 void tst_QStateMachine::globalRestorePolicySetToDoNotRestore() |
|
2713 { |
|
2714 QStateMachine machine; |
|
2715 machine.setGlobalRestorePolicy(QStateMachine::DoNotRestoreProperties); |
|
2716 |
|
2717 QObject *propertyHolder = new QObject(&machine); |
|
2718 propertyHolder->setProperty("a", 1); |
|
2719 propertyHolder->setProperty("b", 2); |
|
2720 |
|
2721 QState *s1 = new QState(&machine); |
|
2722 s1->assignProperty(propertyHolder, "a", 3); |
|
2723 |
|
2724 QState *s2 = new QState(&machine); |
|
2725 s2->assignProperty(propertyHolder, "b", 4); |
|
2726 |
|
2727 QState *s3 = new QState(&machine); |
|
2728 |
|
2729 s1->addTransition(new EventTransition(QEvent::User, s2)); |
|
2730 s2->addTransition(new EventTransition(QEvent::User, s3)); |
|
2731 |
|
2732 machine.setInitialState(s1); |
|
2733 machine.start(); |
|
2734 QCoreApplication::processEvents(); |
|
2735 |
|
2736 QCOMPARE(propertyHolder->property("a").toInt(), 3); |
|
2737 QCOMPARE(propertyHolder->property("b").toInt(), 2); |
|
2738 |
|
2739 machine.postEvent(new QEvent(QEvent::User)); |
|
2740 QCoreApplication::processEvents(); |
|
2741 |
|
2742 QCOMPARE(propertyHolder->property("a").toInt(), 3); |
|
2743 QCOMPARE(propertyHolder->property("b").toInt(), 4); |
|
2744 |
|
2745 machine.postEvent(new QEvent(QEvent::User)); |
|
2746 QCoreApplication::processEvents(); |
|
2747 |
|
2748 QCOMPARE(propertyHolder->property("a").toInt(), 3); |
|
2749 QCOMPARE(propertyHolder->property("b").toInt(), 4); |
|
2750 } |
|
2751 |
|
2752 /* |
|
2753 void tst_QStateMachine::setRestorePolicyToDoNotRestore() |
|
2754 { |
|
2755 QObject *object = new QObject(); |
|
2756 object->setProperty("a", 1); |
|
2757 object->setProperty("b", 2); |
|
2758 |
|
2759 QStateMachine machine; |
|
2760 |
|
2761 QState *S1 = new QState(); |
|
2762 S1->setObjectName("S1"); |
|
2763 S1->assignProperty(object, "a", 3); |
|
2764 S1->setRestorePolicy(QState::DoNotRestoreProperties); |
|
2765 machine.addState(S1); |
|
2766 |
|
2767 QState *S2 = new QState(); |
|
2768 S2->setObjectName("S2"); |
|
2769 S2->assignProperty(object, "b", 5); |
|
2770 S2->setRestorePolicy(QState::DoNotRestoreProperties); |
|
2771 machine.addState(S2); |
|
2772 |
|
2773 QState *S3 = new QState(); |
|
2774 S3->setObjectName("S3"); |
|
2775 S3->setRestorePolicy(QState::DoNotRestoreProperties); |
|
2776 machine.addState(S3); |
|
2777 |
|
2778 QFinalState *S4 = new QFinalState(); |
|
2779 machine.addState(S4); |
|
2780 |
|
2781 S1->addTransition(new EventTransition(QEvent::User, S2)); |
|
2782 S2->addTransition(new EventTransition(QEvent::User, S3)); |
|
2783 S3->addTransition(S4); |
|
2784 |
|
2785 machine.setInitialState(S1); |
|
2786 machine.start(); |
|
2787 QCoreApplication::processEvents(); |
|
2788 |
|
2789 QCOMPARE(object->property("a").toInt(), 3); |
|
2790 QCOMPARE(object->property("b").toInt(), 2); |
|
2791 |
|
2792 machine.postEvent(new QEvent(QEvent::User)); |
|
2793 QCoreApplication::processEvents(); |
|
2794 |
|
2795 QCOMPARE(object->property("a").toInt(), 3); |
|
2796 QCOMPARE(object->property("b").toInt(), 5); |
|
2797 |
|
2798 machine.postEvent(new QEvent(QEvent::User)); |
|
2799 QCoreApplication::processEvents(); |
|
2800 |
|
2801 QCOMPARE(object->property("a").toInt(), 3); |
|
2802 QCOMPARE(object->property("b").toInt(), 5); |
|
2803 } |
|
2804 |
|
2805 void tst_QStateMachine::setGlobalRestorePolicyToGlobalRestore() |
|
2806 { |
|
2807 s_countWarnings = false; |
|
2808 QStateMachine machine; |
|
2809 machine.setGlobalRestorePolicy(QStateMachine::GlobalRestorePolicy); |
|
2810 |
|
2811 QCOMPARE(machine.globalRestorePolicy(), QStateMachine::DoNotRestoreProperties); |
|
2812 QCOMPARE(s_msgType, QtWarningMsg); |
|
2813 |
|
2814 s_msgType = QtDebugMsg; |
|
2815 machine.setGlobalRestorePolicy(QStateMachine::RestoreProperties); |
|
2816 machine.setGlobalRestorePolicy(QStateMachine::GlobalRestorePolicy); |
|
2817 |
|
2818 QCOMPARE(machine.globalRestorePolicy(), QStateMachine::RestoreProperties); |
|
2819 QCOMPARE(s_msgType, QtWarningMsg); |
|
2820 } |
|
2821 |
|
2822 |
|
2823 void tst_QStateMachine::restorePolicyOnChildState() |
|
2824 { |
|
2825 QStateMachine machine; |
|
2826 |
|
2827 QObject *propertyHolder = new QObject(); |
|
2828 propertyHolder->setProperty("a", 1); |
|
2829 propertyHolder->setProperty("b", 2); |
|
2830 |
|
2831 QState *parentState = new QState(&machine); |
|
2832 parentState->setObjectName("parentState"); |
|
2833 |
|
2834 QState *s1 = new QState(parentState); |
|
2835 s1->setRestorePolicy(QState::RestoreProperties); |
|
2836 s1->setObjectName("s1"); |
|
2837 s1->assignProperty(propertyHolder, "a", 3); |
|
2838 parentState->setInitialState(s1); |
|
2839 |
|
2840 QState *s2 = new QState(parentState); |
|
2841 s2->setRestorePolicy(QState::RestoreProperties); |
|
2842 s2->setObjectName("s2"); |
|
2843 s2->assignProperty(propertyHolder, "b", 4); |
|
2844 |
|
2845 QState *s3 = new QState(parentState); |
|
2846 s3->setRestorePolicy(QState::RestoreProperties); |
|
2847 s3->setObjectName("s3"); |
|
2848 |
|
2849 s1->addTransition(new EventTransition(QEvent::User, s2)); |
|
2850 s2->addTransition(new EventTransition(QEvent::User, s3)); |
|
2851 |
|
2852 machine.setInitialState(parentState); |
|
2853 machine.start(); |
|
2854 QCoreApplication::processEvents(); |
|
2855 |
|
2856 QCOMPARE(propertyHolder->property("a").toInt(), 3); |
|
2857 QCOMPARE(propertyHolder->property("b").toInt(), 2); |
|
2858 |
|
2859 machine.postEvent(new QEvent(QEvent::User)); |
|
2860 QCoreApplication::processEvents(); |
|
2861 |
|
2862 QCOMPARE(propertyHolder->property("a").toInt(), 1); |
|
2863 QCOMPARE(propertyHolder->property("b").toInt(), 4); |
|
2864 |
|
2865 machine.postEvent(new QEvent(QEvent::User)); |
|
2866 QCoreApplication::processEvents(); |
|
2867 |
|
2868 QCOMPARE(propertyHolder->property("a").toInt(), 1); |
|
2869 QCOMPARE(propertyHolder->property("b").toInt(), 2); |
|
2870 } |
|
2871 */ |
|
2872 |
|
2873 void tst_QStateMachine::globalRestorePolicySetToRestore() |
|
2874 { |
|
2875 QStateMachine machine; |
|
2876 machine.setGlobalRestorePolicy(QStateMachine::RestoreProperties); |
|
2877 |
|
2878 QObject *propertyHolder = new QObject(&machine); |
|
2879 propertyHolder->setProperty("a", 1); |
|
2880 propertyHolder->setProperty("b", 2); |
|
2881 |
|
2882 QState *s1 = new QState(&machine); |
|
2883 s1->assignProperty(propertyHolder, "a", 3); |
|
2884 |
|
2885 QState *s2 = new QState(&machine); |
|
2886 s2->assignProperty(propertyHolder, "b", 4); |
|
2887 |
|
2888 QState *s3 = new QState(&machine); |
|
2889 |
|
2890 s1->addTransition(new EventTransition(QEvent::User, s2)); |
|
2891 s2->addTransition(new EventTransition(QEvent::User, s3)); |
|
2892 |
|
2893 machine.setInitialState(s1); |
|
2894 machine.start(); |
|
2895 QCoreApplication::processEvents(); |
|
2896 |
|
2897 QCOMPARE(propertyHolder->property("a").toInt(), 3); |
|
2898 QCOMPARE(propertyHolder->property("b").toInt(), 2); |
|
2899 |
|
2900 machine.postEvent(new QEvent(QEvent::User)); |
|
2901 QCoreApplication::processEvents(); |
|
2902 |
|
2903 QCOMPARE(propertyHolder->property("a").toInt(), 1); |
|
2904 QCOMPARE(propertyHolder->property("b").toInt(), 4); |
|
2905 |
|
2906 machine.postEvent(new QEvent(QEvent::User)); |
|
2907 QCoreApplication::processEvents(); |
|
2908 |
|
2909 QCOMPARE(propertyHolder->property("a").toInt(), 1); |
|
2910 QCOMPARE(propertyHolder->property("b").toInt(), 2); |
|
2911 } |
|
2912 |
|
2913 /* |
|
2914 void tst_QStateMachine::mixedRestoreProperties() |
|
2915 { |
|
2916 QStateMachine machine; |
|
2917 |
|
2918 QObject *propertyHolder = new QObject(); |
|
2919 propertyHolder->setProperty("a", 1); |
|
2920 |
|
2921 QState *s1 = new QState(&machine); |
|
2922 s1->setRestorePolicy(QState::RestoreProperties); |
|
2923 s1->assignProperty(propertyHolder, "a", 3); |
|
2924 |
|
2925 QState *s2 = new QState(&machine); |
|
2926 s2->assignProperty(propertyHolder, "a", 4); |
|
2927 |
|
2928 QState *s3 = new QState(&machine); |
|
2929 |
|
2930 QState *s4 = new QState(&machine); |
|
2931 s4->assignProperty(propertyHolder, "a", 5); |
|
2932 |
|
2933 QState *s5 = new QState(&machine); |
|
2934 s5->setRestorePolicy(QState::RestoreProperties); |
|
2935 s5->assignProperty(propertyHolder, "a", 6); |
|
2936 |
|
2937 s1->addTransition(new EventTransition(QEvent::User, s2)); |
|
2938 s2->addTransition(new EventTransition(QEvent::User, s3)); |
|
2939 s3->addTransition(new EventTransition(QEvent::User, s4)); |
|
2940 s4->addTransition(new EventTransition(QEvent::User, s5)); |
|
2941 s5->addTransition(new EventTransition(QEvent::User, s3)); |
|
2942 |
|
2943 machine.setInitialState(s1); |
|
2944 machine.start(); |
|
2945 QCoreApplication::processEvents(); |
|
2946 |
|
2947 // Enter s1, save current |
|
2948 QCOMPARE(propertyHolder->property("a").toInt(), 3); |
|
2949 |
|
2950 machine.postEvent(new QEvent(QEvent::User)); |
|
2951 QCoreApplication::processEvents(); |
|
2952 |
|
2953 // Enter s2, restorePolicy == DoNotRestore, so restore all properties |
|
2954 QCOMPARE(propertyHolder->property("a").toInt(), 4); |
|
2955 |
|
2956 machine.postEvent(new QEvent(QEvent::User)); |
|
2957 QCoreApplication::processEvents(); |
|
2958 |
|
2959 // Enter s3 |
|
2960 QCOMPARE(propertyHolder->property("a").toInt(), 4); |
|
2961 |
|
2962 machine.postEvent(new QEvent(QEvent::User)); |
|
2963 QCoreApplication::processEvents(); |
|
2964 |
|
2965 // Enter s4 |
|
2966 QCOMPARE(propertyHolder->property("a").toInt(), 5); |
|
2967 |
|
2968 machine.postEvent(new QEvent(QEvent::User)); |
|
2969 QCoreApplication::processEvents(); |
|
2970 |
|
2971 // Enter s5, save current |
|
2972 QCOMPARE(propertyHolder->property("a").toInt(), 6); |
|
2973 |
|
2974 machine.postEvent(new QEvent(QEvent::User)); |
|
2975 QCoreApplication::processEvents(); |
|
2976 |
|
2977 // Enter s3, restore |
|
2978 QCOMPARE(propertyHolder->property("a").toInt(), 5); |
|
2979 } |
|
2980 */ |
|
2981 |
|
2982 void tst_QStateMachine::transitionWithParent() |
|
2983 { |
|
2984 QStateMachine machine; |
|
2985 QState *s1 = new QState(&machine); |
|
2986 QState *s2 = new QState(&machine); |
|
2987 EventTransition *trans = new EventTransition(QEvent::User, s2, s1); |
|
2988 QCOMPARE(trans->sourceState(), s1); |
|
2989 QCOMPARE(trans->targetState(), (QAbstractState*)s2); |
|
2990 QCOMPARE(trans->targetStates().size(), 1); |
|
2991 QCOMPARE(trans->targetStates().at(0), (QAbstractState*)s2); |
|
2992 } |
|
2993 |
|
2994 void tst_QStateMachine::simpleAnimation() |
|
2995 { |
|
2996 QStateMachine machine; |
|
2997 |
|
2998 QObject *object = new QObject(&machine); |
|
2999 object->setProperty("fooBar", 1.0); |
|
3000 |
|
3001 QState *s1 = new QState(&machine); |
|
3002 QState *s2 = new QState(&machine); |
|
3003 s2->assignProperty(object, "fooBar", 2.0); |
|
3004 |
|
3005 EventTransition *et = new EventTransition(QEvent::User, s2); |
|
3006 QPropertyAnimation *animation = new QPropertyAnimation(object, "fooBar", s2); |
|
3007 et->addAnimation(animation); |
|
3008 s1->addTransition(et); |
|
3009 |
|
3010 QState *s3 = new QState(&machine); |
|
3011 s2->addTransition(animation, SIGNAL(finished()), s3); |
|
3012 QObject::connect(s3, SIGNAL(entered()), QCoreApplication::instance(), SLOT(quit())); |
|
3013 |
|
3014 machine.setInitialState(s1); |
|
3015 machine.start(); |
|
3016 QCoreApplication::processEvents(); |
|
3017 |
|
3018 machine.postEvent(new QEvent(QEvent::User)); |
|
3019 QCOREAPPLICATION_EXEC(5000); |
|
3020 |
|
3021 QVERIFY(machine.configuration().contains(s3)); |
|
3022 QCOMPARE(object->property("fooBar").toDouble(), 2.0); |
|
3023 } |
|
3024 |
|
3025 class SlotCalledCounter: public QObject |
|
3026 { |
|
3027 Q_OBJECT |
|
3028 public: |
|
3029 SlotCalledCounter() : counter(0) {} |
|
3030 |
|
3031 int counter; |
|
3032 |
|
3033 public slots: |
|
3034 void slot() { counter++; } |
|
3035 }; |
|
3036 |
|
3037 void tst_QStateMachine::twoAnimations() |
|
3038 { |
|
3039 QStateMachine machine; |
|
3040 |
|
3041 QObject *object = new QObject(&machine); |
|
3042 object->setProperty("foo", 1.0); |
|
3043 object->setProperty("bar", 3.0); |
|
3044 |
|
3045 QState *s1 = new QState(&machine); |
|
3046 QState *s2 = new QState(&machine); |
|
3047 s2->assignProperty(object, "foo", 2.0); |
|
3048 s2->assignProperty(object, "bar", 10.0); |
|
3049 |
|
3050 QPropertyAnimation *animationFoo = new QPropertyAnimation(object, "foo", s2); |
|
3051 QPropertyAnimation *animationBar = new QPropertyAnimation(object, "bar", s2); |
|
3052 animationBar->setDuration(900); |
|
3053 |
|
3054 SlotCalledCounter counter; |
|
3055 connect(animationFoo, SIGNAL(finished()), &counter, SLOT(slot())); |
|
3056 connect(animationBar, SIGNAL(finished()), &counter, SLOT(slot())); |
|
3057 |
|
3058 EventTransition *et = new EventTransition(QEvent::User, s2); |
|
3059 et->addAnimation(animationFoo); |
|
3060 et->addAnimation(animationBar); |
|
3061 s1->addTransition(et); |
|
3062 |
|
3063 QState *s3 = new QState(&machine); |
|
3064 QObject::connect(s3, SIGNAL(entered()), QCoreApplication::instance(), SLOT(quit())); |
|
3065 s2->addTransition(s2, SIGNAL(polished()), s3); |
|
3066 |
|
3067 machine.setInitialState(s1); |
|
3068 machine.start(); |
|
3069 QCoreApplication::processEvents(); |
|
3070 |
|
3071 machine.postEvent(new QEvent(QEvent::User)); |
|
3072 QCOREAPPLICATION_EXEC(5000); |
|
3073 |
|
3074 QVERIFY(machine.configuration().contains(s3)); |
|
3075 QCOMPARE(object->property("foo").toDouble(), 2.0); |
|
3076 QCOMPARE(object->property("bar").toDouble(), 10.0); |
|
3077 |
|
3078 QCOMPARE(counter.counter, 2); |
|
3079 } |
|
3080 |
|
3081 void tst_QStateMachine::twoAnimatedTransitions() |
|
3082 { |
|
3083 QStateMachine machine; |
|
3084 |
|
3085 QObject *object = new QObject(&machine); |
|
3086 object->setProperty("foo", 1.0); |
|
3087 |
|
3088 QState *s1 = new QState(&machine); |
|
3089 |
|
3090 QState *s2 = new QState(&machine); |
|
3091 s2->assignProperty(object, "foo", 5.0); |
|
3092 QPropertyAnimation *fooAnimation = new QPropertyAnimation(object, "foo", s2); |
|
3093 s1->addTransition(new EventTransition(QEvent::User, s2))->addAnimation(fooAnimation); |
|
3094 |
|
3095 QState *s3 = new QState(&machine); |
|
3096 QObject::connect(s3, SIGNAL(entered()), QCoreApplication::instance(), SLOT(quit())); |
|
3097 s2->addTransition(fooAnimation, SIGNAL(finished()), s3); |
|
3098 |
|
3099 QState *s4 = new QState(&machine); |
|
3100 s4->assignProperty(object, "foo", 2.0); |
|
3101 QPropertyAnimation *fooAnimation2 = new QPropertyAnimation(object, "foo", s4); |
|
3102 s3->addTransition(new EventTransition(QEvent::User, s4))->addAnimation(fooAnimation2); |
|
3103 |
|
3104 QState *s5 = new QState(&machine); |
|
3105 QObject::connect(s5, SIGNAL(entered()), QApplication::instance(), SLOT(quit())); |
|
3106 s4->addTransition(fooAnimation2, SIGNAL(finished()), s5); |
|
3107 |
|
3108 machine.setInitialState(s1); |
|
3109 machine.start(); |
|
3110 QCoreApplication::processEvents(); |
|
3111 |
|
3112 machine.postEvent(new QEvent(QEvent::User)); |
|
3113 QCOREAPPLICATION_EXEC(5000); |
|
3114 |
|
3115 QVERIFY(machine.configuration().contains(s3)); |
|
3116 QCOMPARE(object->property("foo").toDouble(), 5.0); |
|
3117 |
|
3118 machine.postEvent(new QEvent(QEvent::User)); |
|
3119 QCOREAPPLICATION_EXEC(5000); |
|
3120 |
|
3121 QVERIFY(machine.configuration().contains(s5)); |
|
3122 QCOMPARE(object->property("foo").toDouble(), 2.0); |
|
3123 } |
|
3124 |
|
3125 void tst_QStateMachine::playAnimationTwice() |
|
3126 { |
|
3127 QStateMachine machine; |
|
3128 |
|
3129 QObject *object = new QObject(&machine); |
|
3130 object->setProperty("foo", 1.0); |
|
3131 |
|
3132 QState *s1 = new QState(&machine); |
|
3133 |
|
3134 QState *s2 = new QState(&machine); |
|
3135 s2->assignProperty(object, "foo", 5.0); |
|
3136 QPropertyAnimation *fooAnimation = new QPropertyAnimation(object, "foo", s2); |
|
3137 s1->addTransition(new EventTransition(QEvent::User, s2))->addAnimation(fooAnimation); |
|
3138 |
|
3139 QState *s3 = new QState(&machine); |
|
3140 QObject::connect(s3, SIGNAL(entered()), QCoreApplication::instance(), SLOT(quit())); |
|
3141 s2->addTransition(fooAnimation, SIGNAL(finished()), s3); |
|
3142 |
|
3143 QState *s4 = new QState(&machine); |
|
3144 s4->assignProperty(object, "foo", 2.0); |
|
3145 s3->addTransition(new EventTransition(QEvent::User, s4))->addAnimation(fooAnimation); |
|
3146 |
|
3147 QState *s5 = new QState(&machine); |
|
3148 QObject::connect(s5, SIGNAL(entered()), QApplication::instance(), SLOT(quit())); |
|
3149 s4->addTransition(fooAnimation, SIGNAL(finished()), s5); |
|
3150 |
|
3151 machine.setInitialState(s1); |
|
3152 machine.start(); |
|
3153 QCoreApplication::processEvents(); |
|
3154 |
|
3155 machine.postEvent(new QEvent(QEvent::User)); |
|
3156 QCOREAPPLICATION_EXEC(5000); |
|
3157 |
|
3158 QVERIFY(machine.configuration().contains(s3)); |
|
3159 QCOMPARE(object->property("foo").toDouble(), 5.0); |
|
3160 |
|
3161 machine.postEvent(new QEvent(QEvent::User)); |
|
3162 QCOREAPPLICATION_EXEC(5000); |
|
3163 |
|
3164 QVERIFY(machine.configuration().contains(s5)); |
|
3165 QCOMPARE(object->property("foo").toDouble(), 2.0); |
|
3166 } |
|
3167 |
|
3168 void tst_QStateMachine::nestedTargetStateForAnimation() |
|
3169 { |
|
3170 QStateMachine machine; |
|
3171 |
|
3172 QObject *object = new QObject(&machine); |
|
3173 object->setProperty("foo", 1.0); |
|
3174 object->setProperty("bar", 3.0); |
|
3175 |
|
3176 SlotCalledCounter counter; |
|
3177 |
|
3178 QState *s1 = new QState(&machine); |
|
3179 QState *s2 = new QState(&machine); |
|
3180 |
|
3181 s2->assignProperty(object, "foo", 2.0); |
|
3182 |
|
3183 QState *s2Child = new QState(s2); |
|
3184 s2Child->assignProperty(object, "bar", 10.0); |
|
3185 s2->setInitialState(s2Child); |
|
3186 |
|
3187 QState *s2Child2 = new QState(s2); |
|
3188 s2Child2->assignProperty(object, "bar", 11.0); |
|
3189 QAbstractTransition *at = s2Child->addTransition(new EventTransition(QEvent::User, s2Child2)); |
|
3190 |
|
3191 QPropertyAnimation *animation = new QPropertyAnimation(object, "bar", s2); |
|
3192 animation->setDuration(2000); |
|
3193 connect(animation, SIGNAL(finished()), &counter, SLOT(slot())); |
|
3194 at->addAnimation(animation); |
|
3195 |
|
3196 at = s1->addTransition(new EventTransition(QEvent::User, s2)); |
|
3197 |
|
3198 animation = new QPropertyAnimation(object, "foo", s2); |
|
3199 connect(animation, SIGNAL(finished()), &counter, SLOT(slot())); |
|
3200 at->addAnimation(animation); |
|
3201 |
|
3202 animation = new QPropertyAnimation(object, "bar", s2); |
|
3203 connect(animation, SIGNAL(finished()), &counter, SLOT(slot())); |
|
3204 at->addAnimation(animation); |
|
3205 |
|
3206 QState *s3 = new QState(&machine); |
|
3207 s2->addTransition(s2Child, SIGNAL(polished()), s3); |
|
3208 |
|
3209 QObject::connect(s3, SIGNAL(entered()), QCoreApplication::instance(), SLOT(quit())); |
|
3210 |
|
3211 machine.setInitialState(s1); |
|
3212 machine.start(); |
|
3213 QCoreApplication::processEvents(); |
|
3214 machine.postEvent(new QEvent(QEvent::User)); |
|
3215 |
|
3216 QCOREAPPLICATION_EXEC(5000); |
|
3217 |
|
3218 QVERIFY(machine.configuration().contains(s3)); |
|
3219 QCOMPARE(object->property("foo").toDouble(), 2.0); |
|
3220 QCOMPARE(object->property("bar").toDouble(), 10.0); |
|
3221 QCOMPARE(counter.counter, 2); |
|
3222 } |
|
3223 |
|
3224 void tst_QStateMachine::polishedSignalTransitionsReuseAnimationGroup() |
|
3225 { |
|
3226 QStateMachine machine; |
|
3227 QObject *object = new QObject(&machine); |
|
3228 object->setProperty("foo", 0); |
|
3229 |
|
3230 QState *s1 = new QState(&machine); |
|
3231 s1->assignProperty(object, "foo", 123); |
|
3232 QState *s2 = new QState(&machine); |
|
3233 s2->assignProperty(object, "foo", 456); |
|
3234 QState *s3 = new QState(&machine); |
|
3235 s3->assignProperty(object, "foo", 789); |
|
3236 QFinalState *s4 = new QFinalState(&machine); |
|
3237 |
|
3238 QParallelAnimationGroup animationGroup; |
|
3239 animationGroup.addAnimation(new QPropertyAnimation(object, "foo")); |
|
3240 QSignalSpy animationFinishedSpy(&animationGroup, SIGNAL(finished())); |
|
3241 s1->addTransition(s1, SIGNAL(polished()), s2)->addAnimation(&animationGroup); |
|
3242 s2->addTransition(s2, SIGNAL(polished()), s3)->addAnimation(&animationGroup); |
|
3243 s3->addTransition(s3, SIGNAL(polished()), s4); |
|
3244 |
|
3245 machine.setInitialState(s1); |
|
3246 QSignalSpy machineFinishedSpy(&machine, SIGNAL(finished())); |
|
3247 machine.start(); |
|
3248 QTRY_COMPARE(machineFinishedSpy.count(), 1); |
|
3249 QCOMPARE(machine.configuration().size(), 1); |
|
3250 QVERIFY(machine.configuration().contains(s4)); |
|
3251 QCOMPARE(object->property("foo").toInt(), 789); |
|
3252 |
|
3253 QCOMPARE(animationFinishedSpy.count(), 2); |
|
3254 } |
|
3255 |
|
3256 void tst_QStateMachine::animatedGlobalRestoreProperty() |
|
3257 { |
|
3258 QStateMachine machine; |
|
3259 machine.setGlobalRestorePolicy(QStateMachine::RestoreProperties); |
|
3260 |
|
3261 QObject *object = new QObject(&machine); |
|
3262 object->setProperty("foo", 1.0); |
|
3263 |
|
3264 SlotCalledCounter counter; |
|
3265 |
|
3266 QState *s1 = new QState(&machine); |
|
3267 QState *s2 = new QState(&machine); |
|
3268 s2->assignProperty(object, "foo", 2.0); |
|
3269 |
|
3270 QState *s3 = new QState(&machine); |
|
3271 |
|
3272 QState *s4 = new QState(&machine); |
|
3273 QObject::connect(s4, SIGNAL(entered()), QCoreApplication::instance(), SLOT(quit())); |
|
3274 |
|
3275 QAbstractTransition *at = s1->addTransition(new EventTransition(QEvent::User, s2)); |
|
3276 QPropertyAnimation *pa = new QPropertyAnimation(object, "foo", s2); |
|
3277 connect(pa, SIGNAL(finished()), &counter, SLOT(slot())); |
|
3278 at->addAnimation(pa); |
|
3279 |
|
3280 at = s2->addTransition(pa, SIGNAL(finished()), s3); |
|
3281 pa = new QPropertyAnimation(object, "foo", s3); |
|
3282 connect(pa, SIGNAL(finished()), &counter, SLOT(slot())); |
|
3283 at->addAnimation(pa); |
|
3284 |
|
3285 at = s3->addTransition(pa, SIGNAL(finished()), s4); |
|
3286 pa = new QPropertyAnimation(object, "foo", s4); |
|
3287 connect(pa, SIGNAL(finished()), &counter, SLOT(slot())); |
|
3288 at->addAnimation(pa); |
|
3289 |
|
3290 machine.setInitialState(s1); |
|
3291 machine.start(); |
|
3292 QCoreApplication::processEvents(); |
|
3293 |
|
3294 machine.postEvent(new QEvent(QEvent::User)); |
|
3295 |
|
3296 QCOREAPPLICATION_EXEC(5000); |
|
3297 |
|
3298 QVERIFY(machine.configuration().contains(s4)); |
|
3299 QCOMPARE(object->property("foo").toDouble(), 1.0); |
|
3300 QCOMPARE(counter.counter, 2); |
|
3301 } |
|
3302 |
|
3303 void tst_QStateMachine::specificTargetValueOfAnimation() |
|
3304 { |
|
3305 QStateMachine machine; |
|
3306 |
|
3307 QObject *object = new QObject(&machine); |
|
3308 object->setProperty("foo", 1.0); |
|
3309 |
|
3310 QState *s1 = new QState(&machine); |
|
3311 |
|
3312 QState *s2 = new QState(&machine); |
|
3313 s2->assignProperty(object, "foo", 2.0); |
|
3314 |
|
3315 QPropertyAnimation *anim = new QPropertyAnimation(object, "foo"); |
|
3316 anim->setEndValue(10.0); |
|
3317 s1->addTransition(new EventTransition(QEvent::User, s2))->addAnimation(anim); |
|
3318 |
|
3319 QState *s3 = new QState(&machine); |
|
3320 QObject::connect(s3, SIGNAL(entered()), QCoreApplication::instance(), SLOT(quit())); |
|
3321 s2->addTransition(anim, SIGNAL(finished()), s3); |
|
3322 |
|
3323 machine.setInitialState(s1); |
|
3324 machine.start(); |
|
3325 QCoreApplication::processEvents(); |
|
3326 |
|
3327 machine.postEvent(new QEvent(QEvent::User)); |
|
3328 QCOREAPPLICATION_EXEC(5000); |
|
3329 |
|
3330 QVERIFY(machine.configuration().contains(s3)); |
|
3331 QCOMPARE(object->property("foo").toDouble(), 2.0); |
|
3332 QCOMPARE(anim->endValue().toDouble(), 10.0); |
|
3333 |
|
3334 delete anim; |
|
3335 } |
|
3336 |
|
3337 void tst_QStateMachine::addDefaultAnimation() |
|
3338 { |
|
3339 QStateMachine machine; |
|
3340 |
|
3341 QObject *object = new QObject(); |
|
3342 object->setProperty("foo", 1.0); |
|
3343 |
|
3344 QState *s1 = new QState(&machine); |
|
3345 |
|
3346 QState *s2 = new QState(&machine); |
|
3347 s2->assignProperty(object, "foo", 2.0); |
|
3348 |
|
3349 QState *s3 = new QState(&machine); |
|
3350 QObject::connect(s3, SIGNAL(entered()), QCoreApplication::instance(), SLOT(quit())); |
|
3351 |
|
3352 s1->addTransition(new EventTransition(QEvent::User, s2)); |
|
3353 |
|
3354 QPropertyAnimation *pa = new QPropertyAnimation(object, "foo", &machine); |
|
3355 machine.addDefaultAnimation(pa); |
|
3356 s2->addTransition(pa, SIGNAL(finished()), s3); |
|
3357 |
|
3358 machine.setInitialState(s1); |
|
3359 machine.start(); |
|
3360 QCoreApplication::processEvents(); |
|
3361 |
|
3362 machine.postEvent(new QEvent(QEvent::User)); |
|
3363 QCOREAPPLICATION_EXEC(5000); |
|
3364 |
|
3365 QVERIFY(machine.configuration().contains(s3)); |
|
3366 QCOMPARE(object->property("foo").toDouble(), 2.0); |
|
3367 |
|
3368 delete object; |
|
3369 } |
|
3370 |
|
3371 void tst_QStateMachine::addDefaultAnimationWithUnusedAnimation() |
|
3372 { |
|
3373 QStateMachine machine; |
|
3374 |
|
3375 QObject *object = new QObject(&machine); |
|
3376 object->setProperty("foo", 1.0); |
|
3377 object->setProperty("bar", 2.0); |
|
3378 |
|
3379 SlotCalledCounter counter; |
|
3380 |
|
3381 QState *s1 = new QState(&machine); |
|
3382 |
|
3383 QState *s2 = new QState(&machine); |
|
3384 s2->assignProperty(object, "foo", 2.0); |
|
3385 |
|
3386 QState *s3 = new QState(&machine); |
|
3387 QObject::connect(s3, SIGNAL(entered()), QCoreApplication::instance(), SLOT(quit())); |
|
3388 |
|
3389 s1->addTransition(new EventTransition(QEvent::User, s2)); |
|
3390 |
|
3391 QPropertyAnimation *pa = new QPropertyAnimation(object, "foo", &machine); |
|
3392 connect(pa, SIGNAL(finished()), &counter, SLOT(slot())); |
|
3393 machine.addDefaultAnimation(pa); |
|
3394 s2->addTransition(pa, SIGNAL(finished()), s3); |
|
3395 |
|
3396 pa = new QPropertyAnimation(object, "bar", &machine); |
|
3397 connect(pa, SIGNAL(finished()), &counter, SLOT(slot())); |
|
3398 machine.addDefaultAnimation(pa); |
|
3399 |
|
3400 machine.setInitialState(s1); |
|
3401 machine.start(); |
|
3402 QCoreApplication::processEvents(); |
|
3403 |
|
3404 machine.postEvent(new QEvent(QEvent::User)); |
|
3405 QCOREAPPLICATION_EXEC(5000); |
|
3406 |
|
3407 QVERIFY(machine.configuration().contains(s3)); |
|
3408 QCOMPARE(object->property("foo").toDouble(), 2.0); |
|
3409 QCOMPARE(counter.counter, 1); |
|
3410 } |
|
3411 |
|
3412 void tst_QStateMachine::removeDefaultAnimation() |
|
3413 { |
|
3414 QStateMachine machine; |
|
3415 |
|
3416 QObject propertyHolder; |
|
3417 propertyHolder.setProperty("foo", 0); |
|
3418 |
|
3419 QCOMPARE(machine.defaultAnimations().size(), 0); |
|
3420 |
|
3421 QPropertyAnimation *anim = new QPropertyAnimation(&propertyHolder, "foo"); |
|
3422 |
|
3423 machine.addDefaultAnimation(anim); |
|
3424 |
|
3425 QCOMPARE(machine.defaultAnimations().size(), 1); |
|
3426 QVERIFY(machine.defaultAnimations().contains(anim)); |
|
3427 |
|
3428 machine.removeDefaultAnimation(anim); |
|
3429 |
|
3430 QCOMPARE(machine.defaultAnimations().size(), 0); |
|
3431 |
|
3432 machine.addDefaultAnimation(anim); |
|
3433 |
|
3434 QPropertyAnimation *anim2 = new QPropertyAnimation(&propertyHolder, "foo"); |
|
3435 machine.addDefaultAnimation(anim2); |
|
3436 |
|
3437 QCOMPARE(machine.defaultAnimations().size(), 2); |
|
3438 QVERIFY(machine.defaultAnimations().contains(anim)); |
|
3439 QVERIFY(machine.defaultAnimations().contains(anim2)); |
|
3440 |
|
3441 machine.removeDefaultAnimation(anim); |
|
3442 |
|
3443 QCOMPARE(machine.defaultAnimations().size(), 1); |
|
3444 QVERIFY(machine.defaultAnimations().contains(anim2)); |
|
3445 |
|
3446 machine.removeDefaultAnimation(anim2); |
|
3447 QCOMPARE(machine.defaultAnimations().size(), 0); |
|
3448 |
|
3449 delete anim; |
|
3450 delete anim2; |
|
3451 } |
|
3452 |
|
3453 void tst_QStateMachine::overrideDefaultAnimationWithSpecific() |
|
3454 { |
|
3455 QStateMachine machine; |
|
3456 |
|
3457 QObject *object = new QObject(&machine); |
|
3458 object->setProperty("foo", 1.0); |
|
3459 |
|
3460 SlotCalledCounter counter; |
|
3461 |
|
3462 QState *s1 = new QState(&machine); |
|
3463 machine.setInitialState(s1); |
|
3464 |
|
3465 QState *s2 = new QState(&machine); |
|
3466 s2->assignProperty(object, "foo", 2.0); |
|
3467 |
|
3468 QState *s3 = new QState(&machine); |
|
3469 QObject::connect(s3, SIGNAL(entered()), QCoreApplication::instance(), SLOT(quit())); |
|
3470 |
|
3471 QAbstractTransition *at = s1->addTransition(new EventTransition(QEvent::User, s2)); |
|
3472 |
|
3473 QPropertyAnimation *defaultAnimation = new QPropertyAnimation(object, "foo"); |
|
3474 connect(defaultAnimation, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)), &counter, SLOT(slot())); |
|
3475 |
|
3476 QPropertyAnimation *moreSpecificAnimation = new QPropertyAnimation(object, "foo"); |
|
3477 s2->addTransition(moreSpecificAnimation, SIGNAL(finished()), s3); |
|
3478 connect(moreSpecificAnimation, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)), &counter, SLOT(slot())); |
|
3479 |
|
3480 machine.addDefaultAnimation(defaultAnimation); |
|
3481 at->addAnimation(moreSpecificAnimation); |
|
3482 |
|
3483 machine.start(); |
|
3484 QCoreApplication::processEvents(); |
|
3485 |
|
3486 machine.postEvent(new QEvent(QEvent::User)); |
|
3487 QCOREAPPLICATION_EXEC(5000); |
|
3488 |
|
3489 QVERIFY(machine.configuration().contains(s3)); |
|
3490 QCOMPARE(counter.counter, 2); // specific animation started and stopped |
|
3491 |
|
3492 delete defaultAnimation; |
|
3493 delete moreSpecificAnimation; |
|
3494 } |
|
3495 |
|
3496 /* |
|
3497 void tst_QStateMachine::addDefaultAnimationForSource() |
|
3498 { |
|
3499 QStateMachine machine; |
|
3500 |
|
3501 QObject *object = new QObject(); |
|
3502 object->setProperty("foo", 1.0); |
|
3503 |
|
3504 QState *s1 = new QState(&machine); |
|
3505 |
|
3506 QState *s2 = new QState(&machine); |
|
3507 s2->assignProperty(object, "foo", 2.0); |
|
3508 |
|
3509 QState *s3 = new QState(&machine); |
|
3510 QObject::connect(s3, SIGNAL(entered()), QCoreApplication::instance(), SLOT(quit())); |
|
3511 |
|
3512 s1->addTransition(new EventTransition(QEvent::User, s2)); |
|
3513 |
|
3514 QPropertyAnimation *pa = new QPropertyAnimation(object, "foo", &machine); |
|
3515 machine.addDefaultAnimationForSourceState(s1, pa); |
|
3516 s2->addTransition(pa, SIGNAL(finished()), s3); |
|
3517 |
|
3518 machine.setInitialState(s1); |
|
3519 machine.start(); |
|
3520 QCoreApplication::processEvents(); |
|
3521 |
|
3522 machine.postEvent(new QEvent(QEvent::User)); |
|
3523 QCOREAPPLICATION_EXEC(5000); |
|
3524 |
|
3525 QVERIFY(machine.configuration().contains(s3)); |
|
3526 QCOMPARE(object->property("foo").toDouble(), 2.0); |
|
3527 } |
|
3528 |
|
3529 void tst_QStateMachine::addDefaultAnimationForTarget() |
|
3530 { |
|
3531 QStateMachine machine; |
|
3532 |
|
3533 QObject *object = new QObject(); |
|
3534 object->setProperty("foo", 1.0); |
|
3535 |
|
3536 QState *s1 = new QState(&machine); |
|
3537 |
|
3538 QState *s2 = new QState(&machine); |
|
3539 s2->assignProperty(object, "foo", 2.0); |
|
3540 |
|
3541 QState *s3 = new QState(&machine); |
|
3542 QObject::connect(s3, SIGNAL(entered()), QCoreApplication::instance(), SLOT(quit())); |
|
3543 |
|
3544 s1->addTransition(new EventTransition(QEvent::User, s2)); |
|
3545 |
|
3546 QPropertyAnimation *pa = new QPropertyAnimation(object, "foo", &machine); |
|
3547 machine.addDefaultAnimationForTargetState(s2, pa); |
|
3548 s2->addTransition(pa, SIGNAL(finished()), s3); |
|
3549 |
|
3550 machine.setInitialState(s1); |
|
3551 machine.start(); |
|
3552 QCoreApplication::processEvents(); |
|
3553 |
|
3554 machine.postEvent(new QEvent(QEvent::User)); |
|
3555 QCOREAPPLICATION_EXEC(5000); |
|
3556 |
|
3557 QVERIFY(machine.configuration().contains(s3)); |
|
3558 QCOMPARE(object->property("foo").toDouble(), 2.0); |
|
3559 } |
|
3560 |
|
3561 void tst_QStateMachine::removeDefaultAnimationForSource() |
|
3562 { |
|
3563 QStateMachine machine; |
|
3564 |
|
3565 QCOMPARE(machine.defaultAnimationsForSourceState(&machine).size(), 0); |
|
3566 |
|
3567 QPropertyAnimation *anim = new QPropertyAnimation(this, "foo"); |
|
3568 |
|
3569 machine.addDefaultAnimationForSourceState(&machine, anim); |
|
3570 |
|
3571 QCOMPARE(machine.defaultAnimations().size(), 0); |
|
3572 QCOMPARE(machine.defaultAnimationsForTargetState(&machine).size(), 0); |
|
3573 QCOMPARE(machine.defaultAnimationsForSourceState(&machine).size(), 1); |
|
3574 QVERIFY(machine.defaultAnimationsForSourceState(&machine).contains(anim)); |
|
3575 |
|
3576 machine.removeDefaultAnimationForTargetState(&machine, anim); |
|
3577 |
|
3578 QCOMPARE(machine.defaultAnimations().size(), 0); |
|
3579 QCOMPARE(machine.defaultAnimationsForTargetState(&machine).size(), 0); |
|
3580 QCOMPARE(machine.defaultAnimationsForSourceState(&machine).size(), 1); |
|
3581 QVERIFY(machine.defaultAnimationsForSourceState(&machine).contains(anim)); |
|
3582 |
|
3583 machine.removeDefaultAnimationForSourceState(&machine, anim); |
|
3584 |
|
3585 QCOMPARE(machine.defaultAnimationsForSourceState(&machine).size(), 0); |
|
3586 |
|
3587 machine.addDefaultAnimationForSourceState(&machine, anim); |
|
3588 |
|
3589 QPropertyAnimation *anim2 = new QPropertyAnimation(this, "foo"); |
|
3590 machine.addDefaultAnimationForSourceState(&machine, anim2); |
|
3591 |
|
3592 QCOMPARE(machine.defaultAnimationsForSourceState(&machine).size(), 2); |
|
3593 QVERIFY(machine.defaultAnimationsForSourceState(&machine).contains(anim)); |
|
3594 QVERIFY(machine.defaultAnimationsForSourceState(&machine).contains(anim2)); |
|
3595 |
|
3596 machine.removeDefaultAnimationForSourceState(&machine, anim); |
|
3597 |
|
3598 QCOMPARE(machine.defaultAnimationsForSourceState(&machine).size(), 1); |
|
3599 QVERIFY(machine.defaultAnimationsForSourceState(&machine).contains(anim2)); |
|
3600 |
|
3601 machine.removeDefaultAnimationForSourceState(&machine, anim2); |
|
3602 QCOMPARE(machine.defaultAnimationsForSourceState(&machine).size(), 0); |
|
3603 } |
|
3604 |
|
3605 void tst_QStateMachine::removeDefaultAnimationForTarget() |
|
3606 { |
|
3607 QStateMachine machine; |
|
3608 |
|
3609 QCOMPARE(machine.defaultAnimationsForTargetState(&machine).size(), 0); |
|
3610 |
|
3611 QPropertyAnimation *anim = new QPropertyAnimation(this, "foo"); |
|
3612 |
|
3613 machine.addDefaultAnimationForTargetState(&machine, anim); |
|
3614 |
|
3615 QCOMPARE(machine.defaultAnimations().size(), 0); |
|
3616 QCOMPARE(machine.defaultAnimationsForSourceState(&machine).size(), 0); |
|
3617 QCOMPARE(machine.defaultAnimationsForTargetState(&machine).size(), 1); |
|
3618 QVERIFY(machine.defaultAnimationsForTargetState(&machine).contains(anim)); |
|
3619 |
|
3620 machine.removeDefaultAnimationForSourceState(&machine, anim); |
|
3621 |
|
3622 QCOMPARE(machine.defaultAnimations().size(), 0); |
|
3623 QCOMPARE(machine.defaultAnimationsForSourceState(&machine).size(), 0); |
|
3624 QCOMPARE(machine.defaultAnimationsForTargetState(&machine).size(), 1); |
|
3625 QVERIFY(machine.defaultAnimationsForTargetState(&machine).contains(anim)); |
|
3626 |
|
3627 machine.removeDefaultAnimationForTargetState(&machine, anim); |
|
3628 |
|
3629 QCOMPARE(machine.defaultAnimationsForTargetState(&machine).size(), 0); |
|
3630 |
|
3631 machine.addDefaultAnimationForTargetState(&machine, anim); |
|
3632 |
|
3633 QPropertyAnimation *anim2 = new QPropertyAnimation(this, "foo"); |
|
3634 machine.addDefaultAnimationForTargetState(&machine, anim2); |
|
3635 |
|
3636 QCOMPARE(machine.defaultAnimationsForTargetState(&machine).size(), 2); |
|
3637 QVERIFY(machine.defaultAnimationsForTargetState(&machine).contains(anim)); |
|
3638 QVERIFY(machine.defaultAnimationsForTargetState(&machine).contains(anim2)); |
|
3639 |
|
3640 machine.removeDefaultAnimationForTargetState(&machine, anim); |
|
3641 |
|
3642 QCOMPARE(machine.defaultAnimationsForTargetState(&machine).size(), 1); |
|
3643 QVERIFY(machine.defaultAnimationsForTargetState(&machine).contains(anim2)); |
|
3644 |
|
3645 machine.removeDefaultAnimationForTargetState(&machine, anim2); |
|
3646 QCOMPARE(machine.defaultAnimationsForTargetState(&machine).size(), 0); |
|
3647 } |
|
3648 |
|
3649 void tst_QStateMachine::overrideDefaultAnimationWithSource() |
|
3650 { |
|
3651 QStateMachine machine; |
|
3652 |
|
3653 QObject *object = new QObject(); |
|
3654 object->setProperty("foo", 1.0); |
|
3655 |
|
3656 SlotCalledCounter counter; |
|
3657 |
|
3658 QState *s1 = new QState(&machine); |
|
3659 machine.setInitialState(s1); |
|
3660 |
|
3661 QState *s2 = new QState(&machine); |
|
3662 s2->assignProperty(object, "foo", 2.0); |
|
3663 |
|
3664 QState *s3 = new QState(&machine); |
|
3665 QObject::connect(s3, SIGNAL(entered()), QCoreApplication::instance(), SLOT(quit())); |
|
3666 |
|
3667 s1->addTransition(new EventTransition(QEvent::User, s2)); |
|
3668 |
|
3669 QPropertyAnimation *defaultAnimation = new QPropertyAnimation(object, "foo"); |
|
3670 connect(defaultAnimation, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)), &counter, SLOT(slot())); |
|
3671 |
|
3672 QPropertyAnimation *moreSpecificAnimation = new QPropertyAnimation(object, "foo"); |
|
3673 s2->addTransition(moreSpecificAnimation, SIGNAL(finished()), s3); |
|
3674 connect(moreSpecificAnimation, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)), &counter, SLOT(slot())); |
|
3675 |
|
3676 machine.addDefaultAnimation(defaultAnimation); |
|
3677 machine.addDefaultAnimationForSourceState(s1, moreSpecificAnimation); |
|
3678 |
|
3679 machine.start(); |
|
3680 QCoreApplication::processEvents(); |
|
3681 |
|
3682 machine.postEvent(new QEvent(QEvent::User)); |
|
3683 QCOREAPPLICATION_EXEC(5000); |
|
3684 |
|
3685 QVERIFY(machine.configuration().contains(s3)); |
|
3686 QCOMPARE(counter.counter, 2); // specific animation started and stopped |
|
3687 } |
|
3688 |
|
3689 void tst_QStateMachine::overrideDefaultAnimationWithTarget() |
|
3690 { |
|
3691 QStateMachine machine; |
|
3692 |
|
3693 QObject *object = new QObject(); |
|
3694 object->setProperty("foo", 1.0); |
|
3695 |
|
3696 SlotCalledCounter counter; |
|
3697 |
|
3698 QState *s1 = new QState(&machine); |
|
3699 machine.setInitialState(s1); |
|
3700 |
|
3701 QState *s2 = new QState(&machine); |
|
3702 s2->assignProperty(object, "foo", 2.0); |
|
3703 |
|
3704 QState *s3 = new QState(&machine); |
|
3705 QObject::connect(s3, SIGNAL(entered()), QCoreApplication::instance(), SLOT(quit())); |
|
3706 |
|
3707 s1->addTransition(new EventTransition(QEvent::User, s2)); |
|
3708 |
|
3709 QPropertyAnimation *defaultAnimation = new QPropertyAnimation(object, "foo"); |
|
3710 connect(defaultAnimation, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)), &counter, SLOT(slot())); |
|
3711 |
|
3712 QPropertyAnimation *moreSpecificAnimation = new QPropertyAnimation(object, "foo"); |
|
3713 s2->addTransition(moreSpecificAnimation, SIGNAL(finished()), s3); |
|
3714 connect(moreSpecificAnimation, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)), &counter, SLOT(slot())); |
|
3715 |
|
3716 machine.addDefaultAnimation(defaultAnimation); |
|
3717 machine.addDefaultAnimationForTargetState(s2, moreSpecificAnimation); |
|
3718 |
|
3719 machine.start(); |
|
3720 QCoreApplication::processEvents(); |
|
3721 |
|
3722 machine.postEvent(new QEvent(QEvent::User)); |
|
3723 QCOREAPPLICATION_EXEC(5000); |
|
3724 |
|
3725 QVERIFY(machine.configuration().contains(s3)); |
|
3726 QCOMPARE(counter.counter, 2); // specific animation started and stopped |
|
3727 |
|
3728 } |
|
3729 |
|
3730 void tst_QStateMachine::overrideDefaultSourceAnimationWithSpecific() |
|
3731 { |
|
3732 QStateMachine machine; |
|
3733 |
|
3734 QObject *object = new QObject(); |
|
3735 object->setProperty("foo", 1.0); |
|
3736 |
|
3737 SlotCalledCounter counter; |
|
3738 |
|
3739 QState *s1 = new QState(&machine); |
|
3740 machine.setInitialState(s1); |
|
3741 |
|
3742 QState *s2 = new QState(&machine); |
|
3743 s2->assignProperty(object, "foo", 2.0); |
|
3744 |
|
3745 QState *s3 = new QState(&machine); |
|
3746 QObject::connect(s3, SIGNAL(entered()), QCoreApplication::instance(), SLOT(quit())); |
|
3747 |
|
3748 QAbstractTransition *at = s1->addTransition(new EventTransition(QEvent::User, s2)); |
|
3749 |
|
3750 QPropertyAnimation *defaultAnimation = new QPropertyAnimation(object, "foo"); |
|
3751 connect(defaultAnimation, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)), &counter, SLOT(slot())); |
|
3752 |
|
3753 QPropertyAnimation *moreSpecificAnimation = new QPropertyAnimation(object, "foo"); |
|
3754 s2->addTransition(moreSpecificAnimation, SIGNAL(finished()), s3); |
|
3755 connect(moreSpecificAnimation, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)), &counter, SLOT(slot())); |
|
3756 |
|
3757 machine.addDefaultAnimationForSourceState(s1, defaultAnimation); |
|
3758 at->addAnimation(moreSpecificAnimation); |
|
3759 |
|
3760 machine.start(); |
|
3761 QCoreApplication::processEvents(); |
|
3762 |
|
3763 machine.postEvent(new QEvent(QEvent::User)); |
|
3764 QCOREAPPLICATION_EXEC(5000); |
|
3765 |
|
3766 QVERIFY(machine.configuration().contains(s3)); |
|
3767 QCOMPARE(counter.counter, 2); // specific animation started and stopped |
|
3768 } |
|
3769 |
|
3770 void tst_QStateMachine::overrideDefaultTargetAnimationWithSpecific() |
|
3771 { |
|
3772 QStateMachine machine; |
|
3773 |
|
3774 QObject *object = new QObject(); |
|
3775 object->setProperty("foo", 1.0); |
|
3776 |
|
3777 SlotCalledCounter counter; |
|
3778 |
|
3779 QState *s1 = new QState(&machine); |
|
3780 machine.setInitialState(s1); |
|
3781 |
|
3782 QState *s2 = new QState(&machine); |
|
3783 s2->assignProperty(object, "foo", 2.0); |
|
3784 |
|
3785 QState *s3 = new QState(&machine); |
|
3786 QObject::connect(s3, SIGNAL(entered()), QCoreApplication::instance(), SLOT(quit())); |
|
3787 |
|
3788 QAbstractTransition *at = s1->addTransition(new EventTransition(QEvent::User, s2)); |
|
3789 |
|
3790 QPropertyAnimation *defaultAnimation = new QPropertyAnimation(object, "foo"); |
|
3791 connect(defaultAnimation, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)), &counter, SLOT(slot())); |
|
3792 |
|
3793 QPropertyAnimation *moreSpecificAnimation = new QPropertyAnimation(object, "foo"); |
|
3794 s2->addTransition(moreSpecificAnimation, SIGNAL(finished()), s3); |
|
3795 connect(moreSpecificAnimation, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)), &counter, SLOT(slot())); |
|
3796 |
|
3797 machine.addDefaultAnimationForTargetState(s2, defaultAnimation); |
|
3798 at->addAnimation(moreSpecificAnimation); |
|
3799 |
|
3800 machine.start(); |
|
3801 QCoreApplication::processEvents(); |
|
3802 |
|
3803 machine.postEvent(new QEvent(QEvent::User)); |
|
3804 QCOREAPPLICATION_EXEC(5000); |
|
3805 |
|
3806 QVERIFY(machine.configuration().contains(s3)); |
|
3807 QCOMPARE(counter.counter, 2); // specific animation started and stopped |
|
3808 } |
|
3809 |
|
3810 void tst_QStateMachine::overrideDefaultTargetAnimationWithSource() |
|
3811 { |
|
3812 QStateMachine machine; |
|
3813 |
|
3814 QObject *object = new QObject(); |
|
3815 object->setProperty("foo", 1.0); |
|
3816 |
|
3817 SlotCalledCounter counter; |
|
3818 |
|
3819 QState *s1 = new QState(&machine); |
|
3820 machine.setInitialState(s1); |
|
3821 |
|
3822 QState *s2 = new QState(&machine); |
|
3823 s2->assignProperty(object, "foo", 2.0); |
|
3824 |
|
3825 QState *s3 = new QState(&machine); |
|
3826 QObject::connect(s3, SIGNAL(entered()), QCoreApplication::instance(), SLOT(quit())); |
|
3827 |
|
3828 s1->addTransition(new EventTransition(QEvent::User, s2)); |
|
3829 |
|
3830 QPropertyAnimation *defaultAnimation = new QPropertyAnimation(object, "foo"); |
|
3831 connect(defaultAnimation, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)), &counter, SLOT(slot())); |
|
3832 |
|
3833 QPropertyAnimation *moreSpecificAnimation = new QPropertyAnimation(object, "foo"); |
|
3834 s2->addTransition(moreSpecificAnimation, SIGNAL(finished()), s3); |
|
3835 connect(moreSpecificAnimation, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)), &counter, SLOT(slot())); |
|
3836 |
|
3837 machine.addDefaultAnimationForTargetState(s2, defaultAnimation); |
|
3838 machine.addDefaultAnimationForSourceState(s1, moreSpecificAnimation); |
|
3839 |
|
3840 machine.start(); |
|
3841 QCoreApplication::processEvents(); |
|
3842 |
|
3843 machine.postEvent(new QEvent(QEvent::User)); |
|
3844 QCOREAPPLICATION_EXEC(5000); |
|
3845 |
|
3846 QVERIFY(machine.configuration().contains(s3)); |
|
3847 QCOMPARE(counter.counter, 2); // specific animation started and stopped |
|
3848 } |
|
3849 |
|
3850 */ |
|
3851 |
|
3852 void tst_QStateMachine::parallelStateAssignmentsDone() |
|
3853 { |
|
3854 QStateMachine machine; |
|
3855 |
|
3856 QObject *propertyHolder = new QObject(&machine); |
|
3857 propertyHolder->setProperty("foo", 123); |
|
3858 propertyHolder->setProperty("bar", 456); |
|
3859 propertyHolder->setProperty("zoot", 789); |
|
3860 |
|
3861 QState *s1 = new QState(&machine); |
|
3862 machine.setInitialState(s1); |
|
3863 |
|
3864 QState *parallelState = new QState(QState::ParallelStates, &machine); |
|
3865 parallelState->assignProperty(propertyHolder, "foo", 321); |
|
3866 |
|
3867 QState *s2 = new QState(parallelState); |
|
3868 s2->assignProperty(propertyHolder, "bar", 654); |
|
3869 |
|
3870 QState *s3 = new QState(parallelState); |
|
3871 s3->assignProperty(propertyHolder, "zoot", 987); |
|
3872 |
|
3873 s1->addTransition(new EventTransition(QEvent::User, parallelState)); |
|
3874 machine.start(); |
|
3875 QCoreApplication::processEvents(); |
|
3876 |
|
3877 QCOMPARE(propertyHolder->property("foo").toInt(), 123); |
|
3878 QCOMPARE(propertyHolder->property("bar").toInt(), 456); |
|
3879 QCOMPARE(propertyHolder->property("zoot").toInt(), 789); |
|
3880 |
|
3881 machine.postEvent(new QEvent(QEvent::User)); |
|
3882 QCoreApplication::processEvents(); |
|
3883 |
|
3884 QCOMPARE(propertyHolder->property("foo").toInt(), 321); |
|
3885 QCOMPARE(propertyHolder->property("bar").toInt(), 654); |
|
3886 QCOMPARE(propertyHolder->property("zoot").toInt(), 987); |
|
3887 } |
|
3888 |
|
3889 void tst_QStateMachine::transitionsFromParallelStateWithNoChildren() |
|
3890 { |
|
3891 QStateMachine machine; |
|
3892 |
|
3893 QState *parallelState = new QState(QState::ParallelStates, &machine); |
|
3894 machine.setInitialState(parallelState); |
|
3895 |
|
3896 QState *s1 = new QState(&machine); |
|
3897 parallelState->addTransition(new EventTransition(QEvent::User, s1)); |
|
3898 |
|
3899 machine.start(); |
|
3900 QCoreApplication::processEvents(); |
|
3901 |
|
3902 QCOMPARE(1, machine.configuration().size()); |
|
3903 QVERIFY(machine.configuration().contains(parallelState)); |
|
3904 |
|
3905 machine.postEvent(new QEvent(QEvent::User)); |
|
3906 |
|
3907 QCoreApplication::processEvents(); |
|
3908 |
|
3909 QCOMPARE(1, machine.configuration().size()); |
|
3910 QVERIFY(machine.configuration().contains(s1)); |
|
3911 } |
|
3912 |
|
3913 void tst_QStateMachine::parallelStateTransition() |
|
3914 { |
|
3915 QStateMachine machine; |
|
3916 |
|
3917 QState *parallelState = new QState(QState::ParallelStates, &machine); |
|
3918 machine.setInitialState(parallelState); |
|
3919 |
|
3920 QState *s1 = new QState(parallelState); |
|
3921 QState *s2 = new QState(parallelState); |
|
3922 |
|
3923 QState *s1InitialChild = new QState(s1); |
|
3924 s1->setInitialState(s1InitialChild); |
|
3925 |
|
3926 QState *s2InitialChild = new QState(s2); |
|
3927 s2->setInitialState(s2InitialChild); |
|
3928 |
|
3929 QState *s1OtherChild = new QState(s1); |
|
3930 |
|
3931 s1->addTransition(new EventTransition(QEvent::User, s1OtherChild)); |
|
3932 |
|
3933 machine.start(); |
|
3934 QCoreApplication::processEvents(); |
|
3935 |
|
3936 QVERIFY(machine.configuration().contains(parallelState)); |
|
3937 QVERIFY(machine.configuration().contains(s1)); |
|
3938 QVERIFY(machine.configuration().contains(s2)); |
|
3939 QVERIFY(machine.configuration().contains(s1InitialChild)); |
|
3940 QVERIFY(machine.configuration().contains(s2InitialChild)); |
|
3941 QCOMPARE(machine.configuration().size(), 5); |
|
3942 |
|
3943 machine.postEvent(new QEvent(QEvent::User)); |
|
3944 QCoreApplication::processEvents(); |
|
3945 |
|
3946 QVERIFY(machine.configuration().contains(parallelState)); |
|
3947 |
|
3948 QVERIFY(machine.configuration().contains(s1)); |
|
3949 |
|
3950 QVERIFY(machine.configuration().contains(s2)); |
|
3951 QVERIFY(machine.configuration().contains(s1OtherChild)); |
|
3952 QVERIFY(machine.configuration().contains(s2InitialChild)); |
|
3953 QCOMPARE(machine.configuration().size(), 5); |
|
3954 |
|
3955 } |
|
3956 |
|
3957 void tst_QStateMachine::nestedRestoreProperties() |
|
3958 { |
|
3959 QStateMachine machine; |
|
3960 machine.setGlobalRestorePolicy(QStateMachine::RestoreProperties); |
|
3961 |
|
3962 QObject *propertyHolder = new QObject(&machine); |
|
3963 propertyHolder->setProperty("foo", 1); |
|
3964 propertyHolder->setProperty("bar", 2); |
|
3965 |
|
3966 QState *s1 = new QState(&machine); |
|
3967 machine.setInitialState(s1); |
|
3968 |
|
3969 QState *s2 = new QState(&machine); |
|
3970 s2->assignProperty(propertyHolder, "foo", 3); |
|
3971 |
|
3972 QState *s21 = new QState(s2); |
|
3973 s21->assignProperty(propertyHolder, "bar", 4); |
|
3974 s2->setInitialState(s21); |
|
3975 |
|
3976 QState *s22 = new QState(s2); |
|
3977 s22->assignProperty(propertyHolder, "bar", 5); |
|
3978 |
|
3979 s1->addTransition(new EventTransition(QEvent::User, s2)); |
|
3980 s21->addTransition(new EventTransition(QEvent::User, s22)); |
|
3981 |
|
3982 machine.start(); |
|
3983 QCoreApplication::processEvents(); |
|
3984 |
|
3985 QCOMPARE(machine.configuration().size(), 1); |
|
3986 QVERIFY(machine.configuration().contains(s1)); |
|
3987 QCOMPARE(propertyHolder->property("foo").toInt(), 1); |
|
3988 QCOMPARE(propertyHolder->property("bar").toInt(), 2); |
|
3989 |
|
3990 machine.postEvent(new QEvent(QEvent::User)); |
|
3991 QCoreApplication::processEvents(); |
|
3992 |
|
3993 QCOMPARE(machine.configuration().size(), 2); |
|
3994 QVERIFY(machine.configuration().contains(s2)); |
|
3995 QVERIFY(machine.configuration().contains(s21)); |
|
3996 QCOMPARE(propertyHolder->property("foo").toInt(), 3); |
|
3997 QCOMPARE(propertyHolder->property("bar").toInt(), 4); |
|
3998 |
|
3999 machine.postEvent(new QEvent(QEvent::User)); |
|
4000 QCoreApplication::processEvents(); |
|
4001 |
|
4002 QCOMPARE(machine.configuration().size(), 2); |
|
4003 QVERIFY(machine.configuration().contains(s2)); |
|
4004 QVERIFY(machine.configuration().contains(s22)); |
|
4005 QCOMPARE(propertyHolder->property("foo").toInt(), 3); |
|
4006 QCOMPARE(propertyHolder->property("bar").toInt(), 5); |
|
4007 } |
|
4008 |
|
4009 void tst_QStateMachine::nestedRestoreProperties2() |
|
4010 { |
|
4011 QStateMachine machine; |
|
4012 machine.setGlobalRestorePolicy(QStateMachine::RestoreProperties); |
|
4013 |
|
4014 QObject *propertyHolder = new QObject(&machine); |
|
4015 propertyHolder->setProperty("foo", 1); |
|
4016 propertyHolder->setProperty("bar", 2); |
|
4017 |
|
4018 QState *s1 = new QState(&machine); |
|
4019 machine.setInitialState(s1); |
|
4020 |
|
4021 QState *s2 = new QState(&machine); |
|
4022 s2->assignProperty(propertyHolder, "foo", 3); |
|
4023 |
|
4024 QState *s21 = new QState(s2); |
|
4025 s21->assignProperty(propertyHolder, "bar", 4); |
|
4026 s2->setInitialState(s21); |
|
4027 |
|
4028 QState *s22 = new QState(s2); |
|
4029 s22->assignProperty(propertyHolder, "foo", 6); |
|
4030 s22->assignProperty(propertyHolder, "bar", 5); |
|
4031 |
|
4032 s1->addTransition(new EventTransition(QEvent::User, s2)); |
|
4033 s21->addTransition(new EventTransition(QEvent::User, s22)); |
|
4034 s22->addTransition(new EventTransition(QEvent::User, s21)); |
|
4035 |
|
4036 machine.start(); |
|
4037 QCoreApplication::processEvents(); |
|
4038 |
|
4039 QCOMPARE(machine.configuration().size(), 1); |
|
4040 QVERIFY(machine.configuration().contains(s1)); |
|
4041 QCOMPARE(propertyHolder->property("foo").toInt(), 1); |
|
4042 QCOMPARE(propertyHolder->property("bar").toInt(), 2); |
|
4043 |
|
4044 machine.postEvent(new QEvent(QEvent::User)); |
|
4045 QCoreApplication::processEvents(); |
|
4046 |
|
4047 QCOMPARE(machine.configuration().size(), 2); |
|
4048 QVERIFY(machine.configuration().contains(s2)); |
|
4049 QVERIFY(machine.configuration().contains(s21)); |
|
4050 QCOMPARE(propertyHolder->property("foo").toInt(), 3); |
|
4051 QCOMPARE(propertyHolder->property("bar").toInt(), 4); |
|
4052 |
|
4053 machine.postEvent(new QEvent(QEvent::User)); |
|
4054 QCoreApplication::processEvents(); |
|
4055 |
|
4056 QCOMPARE(machine.configuration().size(), 2); |
|
4057 QVERIFY(machine.configuration().contains(s2)); |
|
4058 QVERIFY(machine.configuration().contains(s22)); |
|
4059 QCOMPARE(propertyHolder->property("foo").toInt(), 6); |
|
4060 QCOMPARE(propertyHolder->property("bar").toInt(), 5); |
|
4061 |
|
4062 machine.postEvent(new QEvent(QEvent::User)); |
|
4063 QCoreApplication::processEvents(); |
|
4064 |
|
4065 QCOMPARE(machine.configuration().size(), 2); |
|
4066 QVERIFY(machine.configuration().contains(s2)); |
|
4067 QVERIFY(machine.configuration().contains(s21)); |
|
4068 QCOMPARE(propertyHolder->property("foo").toInt(), 3); |
|
4069 QCOMPARE(propertyHolder->property("bar").toInt(), 4); |
|
4070 |
|
4071 } |
|
4072 |
|
4073 void tst_QStateMachine::nestedStateMachines() |
|
4074 { |
|
4075 QStateMachine machine; |
|
4076 QState *group = new QState(&machine); |
|
4077 group->setChildMode(QState::ParallelStates); |
|
4078 QStateMachine *subMachines[3]; |
|
4079 for (int i = 0; i < 3; ++i) { |
|
4080 QState *subGroup = new QState(group); |
|
4081 QStateMachine *subMachine = new QStateMachine(subGroup); |
|
4082 { |
|
4083 QState *initial = new QState(subMachine); |
|
4084 QFinalState *done = new QFinalState(subMachine); |
|
4085 initial->addTransition(new EventTransition(QEvent::User, done)); |
|
4086 subMachine->setInitialState(initial); |
|
4087 } |
|
4088 QFinalState *subMachineDone = new QFinalState(subGroup); |
|
4089 subMachine->addTransition(subMachine, SIGNAL(finished()), subMachineDone); |
|
4090 subGroup->setInitialState(subMachine); |
|
4091 subMachines[i] = subMachine; |
|
4092 } |
|
4093 QFinalState *final = new QFinalState(&machine); |
|
4094 group->addTransition(group, SIGNAL(finished()), final); |
|
4095 machine.setInitialState(group); |
|
4096 |
|
4097 QSignalSpy startedSpy(&machine, SIGNAL(started())); |
|
4098 QSignalSpy finishedSpy(&machine, SIGNAL(finished())); |
|
4099 machine.start(); |
|
4100 QTRY_COMPARE(startedSpy.count(), 1); |
|
4101 QTRY_COMPARE(machine.configuration().count(), 1+2*3); |
|
4102 QVERIFY(machine.configuration().contains(group)); |
|
4103 for (int i = 0; i < 3; ++i) |
|
4104 QVERIFY(machine.configuration().contains(subMachines[i])); |
|
4105 |
|
4106 QCoreApplication::processEvents(); // starts the submachines |
|
4107 |
|
4108 for (int i = 0; i < 3; ++i) |
|
4109 subMachines[i]->postEvent(new QEvent(QEvent::User)); |
|
4110 |
|
4111 QTRY_COMPARE(finishedSpy.count(), 1); |
|
4112 } |
|
4113 |
|
4114 void tst_QStateMachine::goToState() |
|
4115 { |
|
4116 QStateMachine machine; |
|
4117 QState *s1 = new QState(&machine); |
|
4118 QState *s2 = new QState(&machine); |
|
4119 machine.setInitialState(s1); |
|
4120 QSignalSpy startedSpy(&machine, SIGNAL(started())); |
|
4121 machine.start(); |
|
4122 QTRY_COMPARE(startedSpy.count(), 1); |
|
4123 |
|
4124 QStateMachinePrivate::get(&machine)->goToState(s2); |
|
4125 QCoreApplication::processEvents(); |
|
4126 QCOMPARE(machine.configuration().size(), 1); |
|
4127 QVERIFY(machine.configuration().contains(s2)); |
|
4128 |
|
4129 QStateMachinePrivate::get(&machine)->goToState(s2); |
|
4130 QCoreApplication::processEvents(); |
|
4131 QCOMPARE(machine.configuration().size(), 1); |
|
4132 QVERIFY(machine.configuration().contains(s2)); |
|
4133 |
|
4134 QStateMachinePrivate::get(&machine)->goToState(s1); |
|
4135 QStateMachinePrivate::get(&machine)->goToState(s2); |
|
4136 QStateMachinePrivate::get(&machine)->goToState(s1); |
|
4137 QCOMPARE(machine.configuration().size(), 1); |
|
4138 QVERIFY(machine.configuration().contains(s2)); |
|
4139 |
|
4140 QCoreApplication::processEvents(); |
|
4141 QCOMPARE(machine.configuration().size(), 1); |
|
4142 QVERIFY(machine.configuration().contains(s1)); |
|
4143 |
|
4144 // go to state in group |
|
4145 QState *s2_1 = new QState(s2); |
|
4146 s2->setInitialState(s2_1); |
|
4147 QStateMachinePrivate::get(&machine)->goToState(s2_1); |
|
4148 QCoreApplication::processEvents(); |
|
4149 QCOMPARE(machine.configuration().size(), 2); |
|
4150 QVERIFY(machine.configuration().contains(s2)); |
|
4151 QVERIFY(machine.configuration().contains(s2_1)); |
|
4152 } |
|
4153 |
|
4154 class CloneSignalTransition : public QSignalTransition |
|
4155 { |
|
4156 public: |
|
4157 CloneSignalTransition(QObject *sender, const char *signal, QAbstractState *target) |
|
4158 : QSignalTransition(sender, signal) |
|
4159 { |
|
4160 setTargetState(target); |
|
4161 } |
|
4162 |
|
4163 void onTransition(QEvent *e) |
|
4164 { |
|
4165 QSignalTransition::onTransition(e); |
|
4166 QStateMachine::SignalEvent *se = static_cast<QStateMachine::SignalEvent*>(e); |
|
4167 eventSignalIndex = se->signalIndex(); |
|
4168 } |
|
4169 |
|
4170 int eventSignalIndex; |
|
4171 }; |
|
4172 |
|
4173 void tst_QStateMachine::task260403_clonedSignals() |
|
4174 { |
|
4175 SignalEmitter emitter; |
|
4176 QStateMachine machine; |
|
4177 QState *s1 = new QState(&machine); |
|
4178 QState *s2 = new QState(&machine); |
|
4179 CloneSignalTransition *t1 = new CloneSignalTransition(&emitter, SIGNAL(signalWithDefaultArg()), s2); |
|
4180 s1->addTransition(t1); |
|
4181 |
|
4182 machine.setInitialState(s1); |
|
4183 machine.start(); |
|
4184 QTest::qWait(1); |
|
4185 |
|
4186 emitter.emitSignalWithDefaultArg(); |
|
4187 QTest::qWait(1); |
|
4188 QCOMPARE(t1->eventSignalIndex, emitter.metaObject()->indexOfSignal("signalWithDefaultArg()")); |
|
4189 } |
|
4190 |
|
4191 QTEST_MAIN(tst_QStateMachine) |
|
4192 #include "tst_qstatemachine.moc" |