220 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			220 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| ///////////////////////////////////////////////////////////////////////////////
 | |
| // Name:        tests/thread/queue.cpp
 | |
| // Purpose:     Unit test for wxMessageQueue
 | |
| // Author:      Evgeniy Tarassov
 | |
| // Created:     31/10/2007
 | |
| // Copyright:   (c) 2007 Evgeniy Tarassov
 | |
| // Licence:     wxWindows licence
 | |
| ///////////////////////////////////////////////////////////////////////////////
 | |
| 
 | |
| // ----------------------------------------------------------------------------
 | |
| // headers
 | |
| // ----------------------------------------------------------------------------
 | |
| 
 | |
| #include "testprec.h"
 | |
| 
 | |
| #ifdef __BORLANDC__
 | |
|     #pragma hdrstop
 | |
| #endif
 | |
| 
 | |
| #ifndef WX_PRECOMP
 | |
|     #include "wx/dynarray.h"
 | |
|     #include "wx/thread.h"
 | |
| #endif // WX_PRECOMP
 | |
| 
 | |
| #include "wx/msgqueue.h"
 | |
| 
 | |
| // ----------------------------------------------------------------------------
 | |
| // test class
 | |
| // ----------------------------------------------------------------------------
 | |
| 
 | |
| class QueueTestCase : public CppUnit::TestCase
 | |
| {
 | |
| public:
 | |
|     QueueTestCase() { }
 | |
| 
 | |
|     enum WaitTestType
 | |
|     {
 | |
|         WaitWithTimeout = 0,
 | |
|         WaitInfinitlyLong
 | |
|     };
 | |
| 
 | |
| private:
 | |
|     typedef wxMessageQueue<int> Queue;
 | |
| 
 | |
|     // This class represents a thread that waits (following WaitTestType type)
 | |
|     // for exactly maxMsgCount messages from its message queue and if another
 | |
|     // MyThread is specified, then every message received is posted
 | |
|     // to that next thread.
 | |
|     class MyThread : public wxThread
 | |
|     {
 | |
|     public:
 | |
|         MyThread(WaitTestType type, MyThread *next, int maxMsgCount)
 | |
|            : wxThread(wxTHREAD_JOINABLE),
 | |
|              m_type(type), m_nextThread(next), m_maxMsgCount(maxMsgCount)
 | |
|         {}
 | |
| 
 | |
|         // thread execution starts here
 | |
|         virtual void *Entry() wxOVERRIDE;
 | |
| 
 | |
|         // Thread message queue
 | |
|         Queue& GetQueue()
 | |
|         {
 | |
|             return m_queue;
 | |
|         }
 | |
| 
 | |
|     private:
 | |
|         WaitTestType m_type;
 | |
|         MyThread*    m_nextThread;
 | |
|         int          m_maxMsgCount;
 | |
|         Queue        m_queue;
 | |
|     };
 | |
| 
 | |
|     WX_DEFINE_ARRAY_PTR(MyThread *, ArrayThread);
 | |
| 
 | |
|     CPPUNIT_TEST_SUITE( QueueTestCase );
 | |
|         CPPUNIT_TEST( TestReceive );
 | |
|         CPPUNIT_TEST( TestReceiveTimeout );
 | |
|     CPPUNIT_TEST_SUITE_END();
 | |
| 
 | |
|     void TestReceive();
 | |
|     void TestReceiveTimeout();
 | |
| 
 | |
|     wxDECLARE_NO_COPY_CLASS(QueueTestCase);
 | |
| };
 | |
| 
 | |
| // register in the unnamed registry so that these tests are run by default
 | |
| CPPUNIT_TEST_SUITE_REGISTRATION( QueueTestCase );
 | |
| 
 | |
| // also include in its own registry so that these tests can be run alone
 | |
| CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( QueueTestCase, "QueueTestCase" );
 | |
| 
 | |
| // this function creates the given number of threads and posts msgCount
 | |
| // messages to the last created thread which, in turn, posts all the messages
 | |
| // it receives to the previously created thread which does the same and so on
 | |
| // in cascade -- at the end, each thread will have received all msgCount
 | |
| // messages directly or indirectly
 | |
| void QueueTestCase::TestReceive()
 | |
| {
 | |
|     const int msgCount = 100;
 | |
|     const int threadCount = 10;
 | |
| 
 | |
|     ArrayThread threads;
 | |
| 
 | |
|     int i;
 | |
|     for ( i = 0; i < threadCount; ++i )
 | |
|     {
 | |
|         MyThread *previousThread = i == 0 ? NULL : threads[i-1];
 | |
|         MyThread *thread =
 | |
|             new MyThread(WaitInfinitlyLong, previousThread, msgCount);
 | |
| 
 | |
|         CPPUNIT_ASSERT_EQUAL ( thread->Create(), wxTHREAD_NO_ERROR );
 | |
|         threads.Add(thread);
 | |
|     }
 | |
| 
 | |
|     for ( i = 0; i < threadCount; ++i )
 | |
|     {
 | |
|         threads[i]->Run();
 | |
|     }
 | |
| 
 | |
|     MyThread* lastThread = threads[threadCount - 1];
 | |
| 
 | |
|     for ( i = 0; i < msgCount; ++i )
 | |
|     {
 | |
|         lastThread->GetQueue().Post(i);
 | |
|     }
 | |
| 
 | |
|     for ( i = 0; i < threadCount; ++i )
 | |
|     {
 | |
|         // each thread should return the number of messages received.
 | |
|         // if it returns a negative, then it detected some problem.
 | |
|         wxThread::ExitCode code = threads[i]->Wait();
 | |
|         CPPUNIT_ASSERT_EQUAL( code, (wxThread::ExitCode)wxMSGQUEUE_NO_ERROR );
 | |
|         delete threads[i];
 | |
|     }
 | |
| }
 | |
| 
 | |
| // this function creates two threads, each one waiting (with a timeout) for
 | |
| // exactly two messages.
 | |
| // Exactly to messages are posted into first thread queue, but
 | |
| // only one message is posted to the second thread queue.
 | |
| // Therefore first thread should return with wxMSGQUEUE_NO_ERROR, but the second
 | |
| // should return wxMSGQUEUUE_TIMEOUT.
 | |
| void QueueTestCase::TestReceiveTimeout()
 | |
| {
 | |
|     MyThread* thread1 = new MyThread(WaitWithTimeout, NULL, 2);
 | |
|     MyThread* thread2 = new MyThread(WaitWithTimeout, NULL, 2);
 | |
| 
 | |
|     CPPUNIT_ASSERT_EQUAL ( thread1->Create(), wxTHREAD_NO_ERROR );
 | |
|     CPPUNIT_ASSERT_EQUAL ( thread2->Create(), wxTHREAD_NO_ERROR );
 | |
| 
 | |
|     thread1->Run();
 | |
|     thread2->Run();
 | |
| 
 | |
|     // Post two messages to the first thread
 | |
|     CPPUNIT_ASSERT_EQUAL( thread1->GetQueue().Post(0), wxMSGQUEUE_NO_ERROR );
 | |
|     CPPUNIT_ASSERT_EQUAL( thread1->GetQueue().Post(1), wxMSGQUEUE_NO_ERROR );
 | |
| 
 | |
|     // ...but only one message to the second
 | |
|     CPPUNIT_ASSERT_EQUAL( thread2->GetQueue().Post(0), wxMSGQUEUE_NO_ERROR );
 | |
| 
 | |
|     wxThread::ExitCode code1 = thread1->Wait();
 | |
|     wxThread::ExitCode code2 = thread2->Wait();
 | |
| 
 | |
|     CPPUNIT_ASSERT_EQUAL( code1, (wxThread::ExitCode)wxMSGQUEUE_NO_ERROR );
 | |
|     CPPUNIT_ASSERT_EQUAL( code2, (wxThread::ExitCode)wxMSGQUEUE_TIMEOUT );
 | |
|     delete thread2;
 | |
|     delete thread1;
 | |
| }
 | |
| 
 | |
| // every thread tries to read exactly m_maxMsgCount messages from its queue
 | |
| // following the waiting strategy specified in m_type. If it succeeds then it
 | |
| // returns 0. Otherwise it returns the error code - one of wxMessageQueueError.
 | |
| void *QueueTestCase::MyThread::Entry()
 | |
| {
 | |
|     int messagesReceived = 0;
 | |
|     while ( messagesReceived < m_maxMsgCount )
 | |
|     {
 | |
|         wxMessageQueueError result;
 | |
|         int msg = -1; // just to suppress "possibly uninitialized" warnings
 | |
| 
 | |
|         if ( m_type == WaitWithTimeout )
 | |
|             result = m_queue.ReceiveTimeout(1000, msg);
 | |
|         else
 | |
|             result = m_queue.Receive(msg);
 | |
| 
 | |
|         if ( result == wxMSGQUEUE_MISC_ERROR )
 | |
|             return (wxThread::ExitCode)wxMSGQUEUE_MISC_ERROR;
 | |
| 
 | |
|         if ( result == wxMSGQUEUE_NO_ERROR )
 | |
|         {
 | |
|             if ( m_nextThread != NULL )
 | |
|             {
 | |
|                 wxMessageQueueError res = m_nextThread->GetQueue().Post(msg);
 | |
| 
 | |
|                 if ( res == wxMSGQUEUE_MISC_ERROR )
 | |
|                     return (wxThread::ExitCode)wxMSGQUEUE_MISC_ERROR;
 | |
| 
 | |
|                 // We can't use Catch asserts outside of the main thread
 | |
|                 // currently, unfortunately.
 | |
|                 wxASSERT( res == wxMSGQUEUE_NO_ERROR );
 | |
|             }
 | |
|             ++messagesReceived;
 | |
|             continue;
 | |
|         }
 | |
| 
 | |
|         wxASSERT( result == wxMSGQUEUE_TIMEOUT );
 | |
| 
 | |
|         break;
 | |
|     }
 | |
| 
 | |
|     if ( messagesReceived != m_maxMsgCount )
 | |
|     {
 | |
|         wxASSERT( m_type == WaitWithTimeout );
 | |
| 
 | |
|         return (wxThread::ExitCode)wxMSGQUEUE_TIMEOUT;
 | |
|     }
 | |
| 
 | |
|     return (wxThread::ExitCode)wxMSGQUEUE_NO_ERROR;
 | |
| }
 |