]>
Commit | Line | Data |
---|---|---|
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 | } |