added a test for wxAtomicDec return value
[wxWidgets.git] / tests / thread / atomic.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: tests/thread/atomic.cpp
3 // Purpose: wxAtomic??? unit test
4 // Author: Armel Asselin
5 // Created: 2006-12-14
6 // RCS-ID: $Id$
7 // Copyright: (c) 2006 Armel Asselin
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 #endif // WX_PRECOMP
22
23 #include "wx/atomic.h"
24 #include "wx/thread.h"
25 #include "wx/dynarray.h"
26 #include "wx/log.h"
27
28 WX_DEFINE_ARRAY_PTR(wxThread *, wxArrayThread);
29
30 // ----------------------------------------------------------------------------
31 // test class
32 // ----------------------------------------------------------------------------
33
34 class AtomicTestCase : public CppUnit::TestCase
35 {
36 public:
37 AtomicTestCase() { }
38
39 private:
40
41 enum ETestType
42 {
43 IncAndDecMixed,
44 IncOnly,
45 DecOnly
46 };
47
48 class MyThread : public wxThread
49 {
50 public:
51 MyThread(wxAtomicInt &operateOn, ETestType testType) : wxThread(wxTHREAD_JOINABLE),
52 m_operateOn(operateOn), m_testType(testType) {}
53
54 // thread execution starts here
55 virtual void *Entry();
56
57 public:
58 wxAtomicInt &m_operateOn;
59 ETestType m_testType;
60 };
61
62 CPPUNIT_TEST_SUITE( AtomicTestCase );
63 CPPUNIT_TEST( TestNoThread );
64 CPPUNIT_TEST( TestDecReturn );
65 CPPUNIT_TEST( TestTwoThreadsMix );
66 CPPUNIT_TEST( TestTenThreadsMix );
67 CPPUNIT_TEST( TestTwoThreadsSeparate );
68 CPPUNIT_TEST( TestTenThreadsSeparate );
69 CPPUNIT_TEST_SUITE_END();
70
71 void TestNoThread();
72 void TestDecReturn();
73 void TestTenThreadsMix() { TestWithThreads(10, IncAndDecMixed); }
74 void TestTwoThreadsMix() { TestWithThreads(2, IncAndDecMixed); }
75 void TestTenThreadsSeparate() { TestWithThreads(10, IncOnly); }
76 void TestTwoThreadsSeparate() { TestWithThreads(2, IncOnly); }
77 void TestWithThreads(int count, ETestType testtype);
78
79 DECLARE_NO_COPY_CLASS(AtomicTestCase)
80 };
81
82 // register in the unnamed registry so that these tests are run by default
83 CPPUNIT_TEST_SUITE_REGISTRATION( AtomicTestCase );
84
85 // also include in it's own registry so that these tests can be run alone
86 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( AtomicTestCase, "AtomicTestCase" );
87
88 void AtomicTestCase::TestNoThread()
89 {
90 wxAtomicInt int1=0, int2=0;
91
92 for (wxInt32 i=0; i<10000000; ++i)
93 {
94 wxAtomicInc(int1);
95 wxAtomicDec(int2);
96 }
97
98 CPPUNIT_ASSERT( int1 == 10000000 );
99 CPPUNIT_ASSERT( int2 == -10000000 );
100 }
101
102 void AtomicTestCase::TestDecReturn()
103 {
104 wxAtomicInt i(0);
105 wxAtomicInc(i);
106 wxAtomicInc(i);
107 CPPUNIT_ASSERT( i == 2 );
108
109 CPPUNIT_ASSERT( wxAtomicDec(i) > 0 );
110 CPPUNIT_ASSERT( wxAtomicDec(i) == 0 );
111 }
112
113 void AtomicTestCase::TestWithThreads(int count, ETestType testType)
114 {
115 wxAtomicInt int1=0;
116
117 wxArrayThread threads;
118
119 int i;
120 for ( i = 0; i < count; ++i )
121 {
122 ETestType actualThreadType;
123 switch(testType)
124 {
125 default:
126 actualThreadType = testType;
127 break;
128 case IncOnly:
129 actualThreadType = (i&1)==0 ? IncOnly : DecOnly;
130 break;
131 }
132
133 MyThread *thread = new MyThread(int1, actualThreadType);
134
135 if ( thread->Create() != wxTHREAD_NO_ERROR )
136 {
137 wxLogError(wxT("Can't create thread!"));
138 }
139 else
140 threads.Add(thread);
141 }
142
143 for ( i = 0; i < count; ++i )
144 {
145 threads[i]->Run();
146 }
147
148
149 for ( i = 0; i < count; ++i )
150 {
151 // each thread should return 0, else it detected some problem
152 CPPUNIT_ASSERT (threads[i]->Wait() == (wxThread::ExitCode)0);
153 }
154
155 CPPUNIT_ASSERT( int1 == 0 );
156 }
157
158 // ----------------------------------------------------------------------------
159
160 void *AtomicTestCase::MyThread::Entry()
161 {
162 wxInt32 negativeValuesSeen = 0;
163
164 for (wxInt32 i=0; i<10000000; ++i)
165 {
166 switch (m_testType)
167 {
168 case AtomicTestCase::IncAndDecMixed:
169 wxAtomicInc(m_operateOn);
170 wxAtomicDec(m_operateOn);
171
172 if (m_operateOn < 0)
173 ++negativeValuesSeen;
174 break;
175
176 case AtomicTestCase::IncOnly:
177 wxAtomicInc(m_operateOn);
178 break;
179
180 case AtomicTestCase::DecOnly:
181 wxAtomicDec(m_operateOn);
182 break;
183 }
184 }
185
186 return (wxThread::ExitCode)negativeValuesSeen;
187 }