1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
|
#include "QueueTests.h"
#include <QtCore/QChar>
#include <QtCore/QObject>
#include <QtCore/QThread>
#include <QtCore/QDebug>
#include <QtTest/QtTest>
#include "AppendCharacterJob.h"
#include <Job.h>
#include <State.h>
#include <QueuePolicy.h>
#include <JobSequence.h>
#include <JobCollection.h>
#include <DebuggingAids.h>
#include <WeaverObserver.h>
#include <DependencyPolicy.h>
#include <ResourceRestrictionPolicy.h>
#include <ThreadWeaver.h>
#include <Thread.h>
// always. ahm. no. never. never show your private parts in public.
#ifdef THREADWEAVER_PRIVATE_API
#error "PARTS OF THREADWEAVER'S PRIVATE API ARE INCLUDED IN PUBLIC HEADERS!"
#endif
QMutex s_GlobalMutex;
LowPriorityAppendCharacterJob::LowPriorityAppendCharacterJob (QChar c, QString* stringref, QObject* parent)
: AppendCharacterJob (c, stringref, parent)
{}
int LowPriorityAppendCharacterJob ::priority() const
{
return -1;
}
HighPriorityAppendCharacterJob::HighPriorityAppendCharacterJob (QChar c, QString* stringref,
QObject* parent)
: AppendCharacterJob (c, stringref, parent)
{}
int HighPriorityAppendCharacterJob::priority() const
{
return 1;
}
SecondThreadThatQueues::SecondThreadThatQueues()
: QThread()
{
}
void SecondThreadThatQueues::run ()
{
QString sequence;
AppendCharacterJob a( 'a', &sequence );
ThreadWeaver::Weaver::instance()->enqueue ( &a );
ThreadWeaver::Weaver::instance()->finish();
QCOMPARE( sequence, QString("a" ) );
}
QueueTests::QueueTests( QObject* parent )
: QObject( parent )
, autoDeleteJob ( 0 )
{
}
void QueueTests::initTestCase ()
{
ThreadWeaver::setDebugLevel ( true, 1 );
}
void QueueTests::SimpleQueuePrioritiesTest() {
ThreadWeaver::Weaver weaver;
weaver.setMaximumNumberOfThreads ( 1 ); // just one thread
QString sequence;
LowPriorityAppendCharacterJob jobA ( QChar( 'a' ), &sequence );
AppendCharacterJob jobB ( QChar( 'b' ), &sequence );
HighPriorityAppendCharacterJob jobC ( QChar( 'c' ), &sequence );
// queue low priority, then normal priority, then high priority
// if priorities are processed correctly, the jobs will be executed in reverse order
weaver.suspend();
weaver.enqueue ( & jobA );
weaver.enqueue ( & jobB );
weaver.enqueue ( & jobC );
weaver.resume();
weaver.finish();
QCOMPARE ( sequence, QString ("cba" ) );
}
void QueueTests::WeaverInitializationTest()
{ // this one mostly tests the sanity of the startup behaviour
ThreadWeaver::Weaver weaver;
QCOMPARE (weaver.currentNumberOfThreads(), 0);
QVERIFY (weaver.isEmpty());
QVERIFY(weaver.isIdle());
QVERIFY(weaver.queueLength() == 0);
weaver.finish();
}
void QueueTests::QueueFromSecondThreadTest()
{
SecondThreadThatQueues thread;
thread.start();
thread.wait();
QVERIFY ( ThreadWeaver::Weaver::instance()->isIdle() );
}
void QueueTests::deleteJob( ThreadWeaver::Job* job)
{ // test that signals are properly emitted (asynchronously, that is):
QVERIFY( thread() == QThread::currentThread() );
QVERIFY( job == autoDeleteJob );
delete job;
autoDeleteJob = 0;
}
void QueueTests::DeleteDoneJobsFromSequenceTest()
{
QString sequence;
autoDeleteJob = new AppendCharacterJob( QChar( 'a' ), &sequence );
AppendCharacterJob b( QChar( 'b' ), &sequence );
AppendCharacterJob c( QChar( 'c' ), &sequence );
ThreadWeaver::JobCollection jobCollection( this );
jobCollection.addJob ( autoDeleteJob );
jobCollection.addJob ( &b );
jobCollection.addJob ( &c);
QVERIFY( autoDeleteJob != 0 );
connect( autoDeleteJob, SIGNAL(done(ThreadWeaver::Job*)),
SLOT(deleteJob(ThreadWeaver::Job*)) );
ThreadWeaver::Weaver::instance()->enqueue ( &jobCollection );
QTest::qWait(100); // return to event queue to make sure signals are delivered
ThreadWeaver::Weaver::instance()->finish();
QTest::qWait(100); // return to event queue to make sure signals are delivered
// no need to delete a, that should be done in deleteJob
QVERIFY( autoDeleteJob == 0 );
}
void QueueTests::deleteCollection( Job* collection )
{
QVERIFY( thread() == QThread::currentThread() );
QVERIFY( collection == autoDeleteCollection );
delete autoDeleteCollection;
autoDeleteCollection = 0;
}
void QueueTests::DeleteCollectionOnDoneTest()
{
QString sequence;
autoDeleteCollection = new ThreadWeaver::JobCollection( this );
connect ( autoDeleteCollection, SIGNAL(done(ThreadWeaver::Job*)),
SLOT(deleteCollection(ThreadWeaver::Job*)) );
AppendCharacterJob a( QChar( 'a' ), &sequence );
AppendCharacterJob b( QChar( 'b' ), &sequence );
autoDeleteCollection->addJob( &a );
autoDeleteCollection->addJob( &b );
ThreadWeaver::Weaver::instance()->enqueue( autoDeleteCollection );
// return to event queue to make sure signals are delivered
// (otherwise, no slot calls would happen before the end of this function)
// I assume the amount of time that we wait does not matter
QTest::qWait(10);
ThreadWeaver::Weaver::instance()->finish();
// return to event queue to make sure signals are delivered
QTest::qWait(10);
// no need to delete a, that should be done in deleteJob
QVERIFY( sequence.length() == 2 );
QVERIFY( autoDeleteCollection == 0 );
}
QTEST_MAIN ( QueueTests )
#include "QueueTests.moc"
|