]> git.saurik.com Git - wxWidgets.git/blob - tests/thread/queue.cpp
Add wx/meta/removeref.h header defining wxRemoveRef<> helper.
[wxWidgets.git] / tests / thread / queue.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: tests/thread/queue.cpp
3 // Purpose: Unit test for wxMessageQueue
4 // Author: Evgeniy Tarassov
5 // Created: 31/10/2007
6 // RCS-ID: $Id$
7 // Copyright: (c) 2007 Evgeniy Tarassov
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
10
11 // ----------------------------------------------------------------------------
12 // headers
13 // ----------------------------------------------------------------------------
14
15 #include "testprec.h"
16
17 #ifdef __BORLANDC__
18 #pragma hdrstop
19 #endif
20
21 #ifndef WX_PRECOMP
22 #include "wx/dynarray.h"
23 #include "wx/thread.h"
24 #endif // WX_PRECOMP
25
26 #include "wx/msgqueue.h"
27
28 // ----------------------------------------------------------------------------
29 // test class
30 // ----------------------------------------------------------------------------
31
32 class QueueTestCase : public CppUnit::TestCase
33 {
34 public:
35 QueueTestCase() { }
36
37 enum WaitTestType
38 {
39 WaitWithTimeout = 0,
40 WaitInfinitlyLong
41 };
42
43 private:
44 typedef wxMessageQueue<int> Queue;
45
46 // This class represents a thread that waits (following WaitTestType type)
47 // for exactly maxMsgCount messages from its message queue and if another
48 // MyThread is specified, then every message received is posted
49 // to that next thread.
50 class MyThread : public wxThread
51 {
52 public:
53 MyThread(WaitTestType type, MyThread *next, int maxMsgCount)
54 : wxThread(wxTHREAD_JOINABLE),
55 m_type(type), m_nextThread(next), m_maxMsgCount(maxMsgCount)
56 {}
57
58 // thread execution starts here
59 virtual void *Entry();
60
61 // Thread message queue
62 Queue& GetQueue()
63 {
64 return m_queue;
65 }
66
67 private:
68 WaitTestType m_type;
69 MyThread* m_nextThread;
70 int m_maxMsgCount;
71 Queue m_queue;
72 };
73
74 WX_DEFINE_ARRAY_PTR(MyThread *, ArrayThread);
75
76 CPPUNIT_TEST_SUITE( QueueTestCase );
77 CPPUNIT_TEST( TestReceive );
78 CPPUNIT_TEST( TestReceiveTimeout );
79 CPPUNIT_TEST_SUITE_END();
80
81 void TestReceive();
82 void TestReceiveTimeout();
83
84 DECLARE_NO_COPY_CLASS(QueueTestCase)
85 };
86
87 // register in the unnamed registry so that these tests are run by default
88 CPPUNIT_TEST_SUITE_REGISTRATION( QueueTestCase );
89
90 // also include in its own registry so that these tests can be run alone
91 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( QueueTestCase, "QueueTestCase" );
92
93 // this function creates the given number of threads and posts msgCount
94 // messages to the last created thread which, in turn, posts all the messages
95 // it receives to the previously created thread which does the same and so on
96 // in cascade -- at the end, each thread will have received all msgCount
97 // messages directly or indirectly
98 void QueueTestCase::TestReceive()
99 {
100 const int msgCount = 100;
101 const int threadCount = 10;
102
103 ArrayThread threads;
104
105 int i;
106 for ( i = 0; i < threadCount; ++i )
107 {
108 MyThread *previousThread = i == 0 ? NULL : threads[i-1];
109 MyThread *thread =
110 new MyThread(WaitInfinitlyLong, previousThread, msgCount);
111
112 CPPUNIT_ASSERT_EQUAL ( thread->Create(), wxTHREAD_NO_ERROR );
113 threads.Add(thread);
114 }
115
116 for ( i = 0; i < threadCount; ++i )
117 {
118 threads[i]->Run();
119 }
120
121 MyThread* lastThread = threads[threadCount - 1];
122
123 for ( i = 0; i < msgCount; ++i )
124 {
125 lastThread->GetQueue().Post(i);
126 }
127
128 for ( i = 0; i < threadCount; ++i )
129 {
130 // each thread should return the number of messages received.
131 // if it returns a negative, then it detected some problem.
132 wxThread::ExitCode code = threads[i]->Wait();
133 CPPUNIT_ASSERT_EQUAL( code, (wxThread::ExitCode)wxMSGQUEUE_NO_ERROR );
134 }
135 }
136
137 // this function creates two threads, each one waiting (with a timeout) for
138 // exactly two messages.
139 // Exactly to messages are posted into first thread queue, but
140 // only one message is posted to the second thread queue.
141 // Therefore first thread should return with wxMSGQUEUE_NO_ERROR, but the second
142 // should return wxMSGQUEUUE_TIMEOUT.
143 void QueueTestCase::TestReceiveTimeout()
144 {
145 MyThread* thread1 = new MyThread(WaitWithTimeout, NULL, 2);
146 MyThread* thread2 = new MyThread(WaitWithTimeout, NULL, 2);
147
148 CPPUNIT_ASSERT_EQUAL ( thread1->Create(), wxTHREAD_NO_ERROR );
149 CPPUNIT_ASSERT_EQUAL ( thread2->Create(), wxTHREAD_NO_ERROR );
150
151 thread1->Run();
152 thread2->Run();
153
154 // Post two messages to the first thread
155 CPPUNIT_ASSERT_EQUAL( thread1->GetQueue().Post(0), wxMSGQUEUE_NO_ERROR );
156 CPPUNIT_ASSERT_EQUAL( thread1->GetQueue().Post(1), wxMSGQUEUE_NO_ERROR );
157
158 // ...but only one message to the second
159 CPPUNIT_ASSERT_EQUAL( thread2->GetQueue().Post(0), wxMSGQUEUE_NO_ERROR );
160
161 wxThread::ExitCode code1 = thread1->Wait();
162 wxThread::ExitCode code2 = thread2->Wait();
163
164 CPPUNIT_ASSERT_EQUAL( code1, (wxThread::ExitCode)wxMSGQUEUE_NO_ERROR );
165 CPPUNIT_ASSERT_EQUAL( code2, (wxThread::ExitCode)wxMSGQUEUE_TIMEOUT );
166 }
167
168 // every thread tries to read exactly m_maxMsgCount messages from its queue
169 // following the waiting strategy specified in m_type. If it succeeds then it
170 // returns 0. Otherwise it returns the error code - one of wxMessageQueueError.
171 void *QueueTestCase::MyThread::Entry()
172 {
173 int messagesReceived = 0;
174 while ( messagesReceived < m_maxMsgCount )
175 {
176 wxMessageQueueError result;
177 int msg = -1; // just to suppress "possibly uninitialized" warnings
178
179 if ( m_type == WaitWithTimeout )
180 result = m_queue.ReceiveTimeout(1000, msg);
181 else
182 result = m_queue.Receive(msg);
183
184 if ( result == wxMSGQUEUE_MISC_ERROR )
185 return (wxThread::ExitCode)wxMSGQUEUE_MISC_ERROR;
186
187 if ( result == wxMSGQUEUE_NO_ERROR )
188 {
189 if ( m_nextThread != NULL )
190 {
191 wxMessageQueueError res = m_nextThread->GetQueue().Post(msg);
192
193 if ( res == wxMSGQUEUE_MISC_ERROR )
194 return (wxThread::ExitCode)wxMSGQUEUE_MISC_ERROR;
195
196 CPPUNIT_ASSERT_EQUAL( wxMSGQUEUE_NO_ERROR, res );
197 }
198 ++messagesReceived;
199 continue;
200 }
201
202 CPPUNIT_ASSERT_EQUAL ( result, wxMSGQUEUE_TIMEOUT );
203
204 break;
205 }
206
207 if ( messagesReceived != m_maxMsgCount )
208 {
209 CPPUNIT_ASSERT_EQUAL( m_type, WaitWithTimeout );
210
211 return (wxThread::ExitCode)wxMSGQUEUE_TIMEOUT;
212 }
213
214 return (wxThread::ExitCode)wxMSGQUEUE_NO_ERROR;
215 }