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