Remove all lines containing cvs/svn "$Id$" keyword.
[wxWidgets.git] / tests / streams / socketstream.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: tests/streams/socketstream.cpp
3 // Purpose: Test wxSocketInputStream/wxSocketOutputStream
4 // Author: Vadim Zeitlin
5 // Copyright: (c) 2008 Vadim Zeitlin
6 // Licence: wxWindows licence
7 ///////////////////////////////////////////////////////////////////////////////
8
9 // For compilers that support precompilation, includes "wx/wx.h".
10 // and "wx/cppunit.h"
11 #include "testprec.h"
12
13 #ifdef __BORLANDC__
14 #pragma hdrstop
15 #endif
16
17 // for all others, include the necessary headers
18 #ifndef WX_PRECOMP
19 #include "wx/log.h"
20 #endif
21
22 #include "wx/socket.h"
23 #include "wx/sckstrm.h"
24 #include "wx/thread.h"
25
26 #include "bstream.h"
27
28 namespace
29 {
30
31 const int TEST_PORT_READ = 0x7778; // arbitrary, chosen because == "wx"
32 const int TEST_PORT_WRITE = 0x7779; // well, "wy"
33
34 // these cond and mutex are used to minimize the risk of the main thread
35 // Connect()-ing before this thread starts Accept()-ing connections but
36 // unfortunately we can't make this truly safe, see comment in
37 // SocketServerThread::Entry()
38 wxMutex gs_mutex;
39 wxCondition gs_cond(gs_mutex);
40 } // anonymous namespace
41
42 // return address for the given port on local host
43 static inline wxIPV4address LocalAddress(int port)
44 {
45 wxIPV4address addr;
46 addr.LocalHost();
47 addr.Service(port);
48
49 return addr;
50 }
51
52 // A thread which creates a listening socket on the specified port and executes
53 // the given function with each socket which connects to it
54 class SocketServerThread : public wxThread
55 {
56 public:
57 // port is the port to listen on and function will be called on each
58 // accepted socket
59 SocketServerThread(int port, void (*accept)(wxSocketBase&))
60 : wxThread(wxTHREAD_JOINABLE),
61 m_port(port),
62 m_accept(accept)
63 {
64 Create();
65 Run();
66 }
67
68 protected:
69 virtual void *Entry()
70 {
71 wxSocketServer srv(LocalAddress(m_port), wxSOCKET_REUSEADDR);
72
73 // FIXME: this is still not atomic, of course and the main thread could
74 // call Connect() before we have time to Accept() but there is
75 // no way to fix it with current API
76 {
77 wxMutexLocker lock(gs_mutex);
78 gs_cond.Signal();
79 }
80
81 wxSocketBase *socket = srv.Accept();
82 if ( socket )
83 {
84 (*m_accept)(*socket);
85 delete socket;
86 }
87
88 return NULL;
89 }
90
91 int m_port;
92 void (*m_accept)(wxSocketBase&);
93
94 DECLARE_NO_COPY_CLASS(SocketServerThread)
95 };
96
97 // The test case for socket streams
98 class socketStream :
99 public BaseStreamTestCase<wxSocketInputStream, wxSocketOutputStream>
100 {
101 public:
102 socketStream();
103 virtual ~socketStream();
104
105 virtual void setUp();
106 virtual void tearDown();
107
108 // repeat all socket tests several times with different socket flags, so we
109 // define this macro which is used several times in the test suite
110 //
111 // there must be some more elegant way to do this but I didn't find it...
112 #define ALL_SOCKET_TESTS() \
113 CPPUNIT_TEST(Input_GetC); \
114 CPPUNIT_TEST(Input_Eof); \
115 CPPUNIT_TEST(Input_Read); \
116 CPPUNIT_TEST(Input_LastRead); \
117 CPPUNIT_TEST(Input_CanRead); \
118 CPPUNIT_TEST(Input_Peek); \
119 CPPUNIT_TEST(Input_Ungetch); \
120 \
121 CPPUNIT_TEST(Output_PutC); \
122 CPPUNIT_TEST(Output_Write); \
123 CPPUNIT_TEST(Output_LastWrite)
124
125 CPPUNIT_TEST_SUITE(socketStream);
126 ALL_SOCKET_TESTS();
127 // some tests don't pass with NOWAIT flag but this is probably not a
128 // bug (TODO: check this)
129 #if 0
130 CPPUNIT_TEST( PseudoTest_SetNoWait );
131 ALL_SOCKET_TESTS();
132 #endif
133 CPPUNIT_TEST( PseudoTest_SetWaitAll );
134 ALL_SOCKET_TESTS();
135 CPPUNIT_TEST_SUITE_END();
136
137 private:
138 // Implement base class functions.
139 virtual wxSocketInputStream *DoCreateInStream();
140 virtual wxSocketOutputStream *DoCreateOutStream();
141
142 // socket thread functions
143 static void WriteSocket(wxSocketBase& socket)
144 {
145 socket.Write("hello, world!", 13);
146 }
147
148 static void ReadSocket(wxSocketBase& socket)
149 {
150 char ch;
151 while ( socket.Read(&ch, 1).LastCount() == 1 )
152 ;
153 }
154
155 void PseudoTest_SetNoWait() { ms_flags = wxSOCKET_NOWAIT; }
156 void PseudoTest_SetWaitAll() { ms_flags = wxSOCKET_WAITALL; }
157
158 wxSocketClient *m_readSocket,
159 *m_writeSocket;
160 wxThread *m_writeThread,
161 *m_readThread;
162
163 static wxSocketFlags ms_flags;
164 };
165
166 wxSocketFlags socketStream::ms_flags = wxSOCKET_NONE;
167
168 socketStream::socketStream()
169 {
170 m_readSocket =
171 m_writeSocket = NULL;
172
173 m_writeThread =
174 m_readThread = NULL;
175
176 wxSocketBase::Initialize();
177 }
178
179 socketStream::~socketStream()
180 {
181 wxSocketBase::Shutdown();
182 }
183
184 void socketStream::setUp()
185 {
186 // create the socket threads and wait until they are ready to accept
187 // connections (if we called Connect() before this happens, it would fail)
188 {
189 wxMutexLocker lock(gs_mutex);
190
191 m_writeThread =
192 new SocketServerThread(TEST_PORT_READ, &socketStream::WriteSocket);
193 CPPUNIT_ASSERT_EQUAL( wxCOND_NO_ERROR, gs_cond.Wait() );
194
195 m_readThread =
196 new SocketServerThread(TEST_PORT_WRITE, &socketStream::ReadSocket);
197 CPPUNIT_ASSERT_EQUAL( wxCOND_NO_ERROR, gs_cond.Wait() );
198 }
199
200 m_readSocket = new wxSocketClient(ms_flags);
201 CPPUNIT_ASSERT( m_readSocket->Connect(LocalAddress(TEST_PORT_READ)) );
202
203 m_writeSocket = new wxSocketClient(ms_flags);
204 CPPUNIT_ASSERT( m_writeSocket->Connect(LocalAddress(TEST_PORT_WRITE)) );
205 }
206
207 void socketStream::tearDown()
208 {
209 wxDELETE(m_readSocket);
210 wxDELETE(m_writeSocket);
211
212 m_writeThread->Wait();
213 wxDELETE(m_writeThread);
214
215 m_readThread->Wait();
216 wxDELETE(m_readThread);
217 }
218
219 wxSocketInputStream *socketStream::DoCreateInStream()
220 {
221 wxSocketInputStream *pStrInStream = new wxSocketInputStream(*m_readSocket);
222 CPPUNIT_ASSERT(pStrInStream->IsOk());
223 return pStrInStream;
224 }
225
226 wxSocketOutputStream *socketStream::DoCreateOutStream()
227 {
228 wxSocketOutputStream *pStrOutStream = new wxSocketOutputStream(*m_writeSocket);
229 CPPUNIT_ASSERT(pStrOutStream->IsOk());
230 return pStrOutStream;
231 }
232
233 // Register the stream sub suite, by using some stream helper macro.
234 STREAM_TEST_SUBSUITE_NAMED_REGISTRATION(socketStream)