skip calls of TellI/TellO() if the stream is not seekable; more const-correctness
[wxWidgets.git] / tests / streams / bstream.h
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: tests/streams/bstream.h
3 // Purpose: Template class for testing base stream functions.
4 // Author: Hans Van Leemputten
5 // RCS-ID: $Id$
6 // Copyright: (c) 2004 Hans Van Leemputten
7 // Licence: wxWidgets licence
8 ///////////////////////////////////////////////////////////////////////////////
9
10 #ifndef _WX_TESTBSTREAM_H__
11 #define _WX_TESTBSTREAM_H__
12
13 #include "wx/cppunit.h"
14
15 ///////////////////////////////////////////////////////////////////////////////
16 // Some macros preventing us from typing too much ;-)
17 //
18
19 #define STREAM_TEST_NAME "Streams"
20 #define COMPOSE_TEST_NAME(Name) \
21 STREAM_TEST_NAME "." #Name
22 #define STREAM_REGISTER_SUB_SUITE(Name) \
23 extern CppUnit::Test* Get##Name##Suite(); \
24 suite->addTest(Get##Name##Suite())
25 #define STREAM_IMPLEMENT_SUB_REGISTRATION_ROUTINE(Name) \
26 CppUnit::Test* Get##Name##Suite() { return Name::suite(); }
27 #define STREAM_TEST_SUBSUITE_NAMED_REGISTRATION(Name) \
28 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( Name, COMPOSE_TEST_NAME(Name) ); \
29 STREAM_IMPLEMENT_SUB_REGISTRATION_ROUTINE( Name )
30
31
32 ///////////////////////////////////////////////////////////////////////////////
33 // Template class that implements a test for all base stream functions.
34 //
35
36 template <class TStreamIn, class TStreamOut> class BaseStreamTestCase : public CppUnit::TestCase
37 {
38 protected:
39 typedef BaseStreamTestCase<TStreamIn, TStreamOut> StreamTestCase;
40
41 class CleanupHelper
42 {
43 public:
44 CleanupHelper(StreamTestCase *value)
45 :m_pCleanup(value)
46 {}
47 ~CleanupHelper()
48 {
49 m_pCleanup->DeleteInStream();
50 m_pCleanup->DeleteOutStream();
51 }
52 private:
53 StreamTestCase *m_pCleanup;
54 };
55 friend class CleanupHelper;
56
57 public:
58 BaseStreamTestCase()
59 :m_bSimpleTellITest(false),
60 m_bSimpleTellOTest(false),
61 m_bSeekInvalidBeyondEnd(true),
62 m_bEofAtLastRead(true),
63 m_pCurrentIn(NULL),
64 m_pCurrentOut(NULL)
65 { /* Nothing extra */ }
66 virtual ~BaseStreamTestCase()
67 {
68 // Prevent mem leaks!
69 delete m_pCurrentIn;
70 delete m_pCurrentOut;
71 }
72
73 protected:
74 /*
75 * Input stream tests.
76 */
77
78 // Just try to perform a GetSize() on the input stream.
79 void Input_GetSize()
80 {
81 CleanupHelper cleanup(this);
82 const TStreamIn &stream_in = CreateInStream();
83 CPPUNIT_ASSERT(!stream_in.Eof());
84
85 // Size should be greater then zero.
86 // Note: streams not supporting this should register this test
87 // with CPPUNIT_TEST_FAIL instead of CPPUNIT_TEST.
88 CPPUNIT_ASSERT(stream_in.GetSize() != 0);
89 }
90
91 // Just try to perform a GetC() on the input stream.
92 void Input_GetC()
93 {
94 CleanupHelper cleanup(this);
95 TStreamIn &stream_in = CreateInStream();
96 CPPUNIT_ASSERT(!stream_in.Eof());
97
98 // If no exception occurs the test is successful.
99 (void)stream_in.GetC();
100 }
101
102 // Just try to perform a Read() on the input stream.
103 void Input_Read()
104 {
105 CleanupHelper cleanup(this);
106 TStreamIn &stream_in = CreateInStream();
107 CPPUNIT_ASSERT(!stream_in.Eof());
108
109 // Note: the input stream should at least be of min size +10!
110
111 char buf[10];
112 (void)stream_in.Read(buf, 10);
113
114 CPPUNIT_ASSERT(!stream_in.Eof());
115 CPPUNIT_ASSERT(stream_in.IsOk());
116
117 // Test the stream version aswell.
118 TStreamOut &stream_out = CreateOutStream();
119 (void)stream_in.Read(stream_out);
120
121 // The output stream should have read the input stream till the end.
122 CPPUNIT_ASSERT(stream_in.Eof());
123 }
124
125 // Test and see what happens to the EOF when we
126 // read after EOF was encountered.
127 void Input_Eof()
128 {
129 CleanupHelper cleanup(this);
130 TStreamIn &stream_in = CreateInStream();
131 CPPUNIT_ASSERT(!stream_in.Eof());
132 // Double check to see if Eof it self doesn't changes the Eof status.
133 CPPUNIT_ASSERT(!stream_in.Eof());
134
135 // Travel to the end of the stream.
136 while(!stream_in.Eof())
137 {
138 // Read, we move one byte along.
139 (void)stream_in.GetC();
140 #if 0
141 // EOF behaviour is different in streams, disabled (for now?)
142
143 if (m_bEofAtLastRead)
144 // EOF should only occure after the last successful get.
145 CPPUNIT_ASSERT_MESSAGE("Eof is detected too late.", !(stream_in.LastRead() != 1 && stream_in.Eof()));
146 else
147 // EOF should only occure after a failed get.
148 CPPUNIT_ASSERT_MESSAGE("Eof is detected too soon.", !(stream_in.LastRead() == 1 && stream_in.Eof()));
149 #endif
150 }
151
152 // Check EOF stream state.
153 CPPUNIT_ASSERT_MESSAGE("EOF is not EOF?", stream_in.Eof());
154
155 // Ok we found the end, lets see if we can go past it.
156 for (size_t i = 0; i < 100; i++)
157 (void)stream_in.GetC();
158
159 // Check for EOF correctness.
160 CPPUNIT_ASSERT_MESSAGE("EOF is wrong when we read past EOF!", stream_in.Eof());
161 CPPUNIT_ASSERT_MESSAGE("Last error is not EOF while stream_in.Eof() is true", stream_in.GetLastError() == wxSTREAM_EOF);
162 }
163
164 // Just try to perform a LastRead() on the input stream.
165 void Input_LastRead()
166 {
167 CleanupHelper cleanup(this);
168 TStreamIn &stream_in = CreateInStream();
169 CPPUNIT_ASSERT(!stream_in.Eof());
170
171 char buf[5];
172 (void)stream_in.Read(buf, 5);
173 CPPUNIT_ASSERT(stream_in.LastRead() == 5);
174 (void)stream_in.GetC();
175 CPPUNIT_ASSERT(stream_in.LastRead() == 1);
176 }
177
178 void Input_CanRead()
179 {
180 CleanupHelper cleanup(this);
181 TStreamIn &stream_in = CreateInStream();
182
183 CPPUNIT_ASSERT( stream_in.CanRead() );
184
185 // read the entire contents
186 (void)stream_in.Read(CreateOutStream());
187
188 CPPUNIT_ASSERT( !stream_in.CanRead() );
189 }
190
191 // Just try to perform a SeekI() on the input stream.
192 void Input_SeekI()
193 {
194 CleanupHelper cleanup(this);
195 TStreamIn &stream_in = CreateInStream();
196
197 CPPUNIT_ASSERT( stream_in.IsSeekable() );
198 CPPUNIT_ASSERT(!stream_in.Eof());
199
200 // Try to Seek in the stream...
201 // Note: streams not supporting this should register this test
202 // with CPPUNIT_TEST_FAIL instead of CPPUNIT_TEST.
203 CPPUNIT_ASSERT(stream_in.SeekI(2, wxFromStart) == 2);
204 CPPUNIT_ASSERT(stream_in.SeekI(2, wxFromCurrent) == 4);
205 // Not sure the following line is correct, so test it differently.
206 //CPPUNIT_ASSERT(stream_in.SeekI(-2, wxFromEnd) == (off_t)stream_in.GetSize()-2);
207 CPPUNIT_ASSERT(stream_in.SeekI(-2, wxFromEnd) != wxInvalidOffset);
208 // Go beyond the stream size.
209 CPPUNIT_ASSERT((stream_in.SeekI(10, wxFromCurrent) == wxInvalidOffset) == m_bSeekInvalidBeyondEnd);
210 }
211
212 // Just try to perform a TellI() on the input stream.
213 void Input_TellI()
214 {
215 CleanupHelper cleanup(this);
216 TStreamIn &stream_in = CreateInStream();
217
218 // this test shouldn't be used at all if the stream isn't seekable
219 CPPUNIT_ASSERT( stream_in.IsSeekable() );
220
221 CPPUNIT_ASSERT(!stream_in.Eof());
222
223 // Try to Get the location in the stream...
224 CPPUNIT_ASSERT(stream_in.TellI() == 0);
225 (void)stream_in.GetC();
226 CPPUNIT_ASSERT(stream_in.TellI() == 1);
227 if (!m_bSimpleTellITest)
228 {
229 wxFileOffset pos = stream_in.SeekI(5, wxFromStart);
230 CPPUNIT_ASSERT(stream_in.TellI() == pos);
231 (void)stream_in.GetC();
232 CPPUNIT_ASSERT(stream_in.TellI() == 6);
233 pos = stream_in.SeekI(2, wxFromCurrent);
234 CPPUNIT_ASSERT(stream_in.TellI() == pos);
235 pos = stream_in.SeekI(5, wxFromStart);
236 CPPUNIT_ASSERT(stream_in.TellI() == pos);
237 }
238 }
239
240 // Just try to perform a Peek() on the input stream.
241 void Input_Peek()
242 {
243 CleanupHelper cleanup(this);
244 TStreamIn &stream_in = CreateInStream();
245
246 // Test the full stream
247 while (stream_in.IsOk())
248 {
249 char peekChar = stream_in.Peek();
250 char getChar = stream_in.GetC();
251 if (stream_in.LastRead() == 1)
252 CPPUNIT_ASSERT(peekChar == getChar);
253 }
254 }
255
256 // Just try to perform a Ungetch() on the input stream.
257 void Input_Ungetch()
258 {
259 CleanupHelper cleanup(this);
260 TStreamIn &stream_in = CreateInStream();
261 CPPUNIT_ASSERT(!stream_in.Eof());
262
263 const char *ungetstr = "test";
264 size_t ungetsize = stream_in.Ungetch(ungetstr, strlen(ungetstr) + 1);
265 if (ungetsize != 0)
266 {
267 CPPUNIT_ASSERT(ungetsize == strlen(ungetstr) + 1);
268 char buf[10];
269 (void)stream_in.Read(buf, ungetsize);
270 CPPUNIT_ASSERT(strcmp(buf, ungetstr) == 0);
271 }
272
273 if (stream_in.Ungetch('a'))
274 {
275 CPPUNIT_ASSERT(stream_in.GetC() == 'a');
276 }
277 }
278
279 /*
280 * Output stream tests.
281 */
282
283 // Just try to perform a PutC() on the output stream.
284 void Output_PutC()
285 {
286 CleanupHelper cleanup(this);
287 TStreamOut &stream_out = CreateOutStream();
288
289 const char *buf = "Some text";
290 const wxFileOffset len = strlen(buf);
291 for ( int i = 0; i < len; i++ )
292 stream_out.PutC(buf[i]);
293
294 if ( stream_out.IsSeekable() )
295 CPPUNIT_ASSERT_EQUAL(len, stream_out.TellO());
296 }
297
298 // Just try to perform a Write() on the output stream.
299 void Output_Write()
300 {
301 CleanupHelper cleanup(this);
302 TStreamOut &stream_out = CreateOutStream();
303
304 // Do the buffer version.
305 const char *buf = "Some text";
306 const wxFileOffset len = strlen(buf);
307 (void)stream_out.Write(buf, len);
308 if ( stream_out.IsSeekable() )
309 CPPUNIT_ASSERT_EQUAL( len, stream_out.TellO() );
310
311 // Do the Stream version.
312 TStreamIn &stream_in = CreateInStream();
313 (void)stream_out.Write(stream_in);
314
315 if ( stream_out.IsSeekable() )
316 CPPUNIT_ASSERT(stream_out.TellO() > len);
317 }
318
319 // Just try to perform a LastWrite() on the output stream.
320 void Output_LastWrite()
321 {
322 CleanupHelper cleanup(this);
323 TStreamOut &stream_out = CreateOutStream();
324
325 const char *buf = "12345";
326 (void)stream_out.Write(buf, 5);
327 CPPUNIT_ASSERT(stream_out.LastWrite() == 5);
328 (void)stream_out.PutC('1');
329 CPPUNIT_ASSERT(stream_out.LastWrite() == 1);
330 }
331
332 // Just try to perform a SeekO() on the output stream.
333 void Output_SeekO()
334 {
335 CleanupHelper cleanup(this);
336 TStreamOut &stream_out = CreateOutStream();
337
338 CPPUNIT_ASSERT( stream_out.IsSeekable() );
339
340 // First put some data in the stream, so it is not empty.
341 const char *buf = "1234567890";
342 (void)stream_out.Write(buf, 10);
343
344 // Try to Seek in the stream...
345 // Note: streams not supporting this should register this test
346 // with CPPUNIT_TEST_FAIL instead of CPPUNIT_TEST.
347 CPPUNIT_ASSERT(stream_out.SeekO(2, wxFromStart) == 2);
348 CPPUNIT_ASSERT(stream_out.SeekO(2, wxFromCurrent) == 4);
349 // Not sure the following line is correct, so test it differently.
350 //CPPUNIT_ASSERT(stream_out.SeekO(-2, wxFromEnd) == (off_t)stream_in.GetSize()-2);
351 CPPUNIT_ASSERT(stream_out.SeekO(-2, wxFromEnd) != wxInvalidOffset);
352 // Go beyond the stream size.
353 CPPUNIT_ASSERT((stream_out.SeekO(10, wxFromCurrent) == wxInvalidOffset) == m_bSeekInvalidBeyondEnd);
354 }
355
356 // Just try to perform a TellO() on the output stream.
357 void Output_TellO()
358 {
359 CleanupHelper cleanup(this);
360 TStreamOut &stream_out = CreateOutStream();
361
362 // If this test is used, the stream must be seekable
363 CPPUNIT_ASSERT( stream_out.IsSeekable() );
364
365 // Try to Get the location in the stream...
366 CPPUNIT_ASSERT(stream_out.TellO() == 0);
367 (void)stream_out.PutC('1');
368 CPPUNIT_ASSERT(stream_out.TellO() == 1);
369 if (!m_bSimpleTellOTest)
370 {
371 // First put some extra data in the stream, so it's not empty.
372 const char *buf = "1234567890";
373 (void)stream_out.Write(buf, 10);
374
375 off_t pos = stream_out.SeekO(5, wxFromStart);
376 CPPUNIT_ASSERT(stream_out.TellO() == pos);
377 (void)stream_out.PutC('1');
378 CPPUNIT_ASSERT(stream_out.TellO() == 6);
379 pos = stream_out.SeekO(2, wxFromCurrent);
380 CPPUNIT_ASSERT(stream_out.TellO() == pos);
381 pos = stream_out.SeekO(5, wxFromStart);
382 CPPUNIT_ASSERT(stream_out.TellO() == pos);
383 }
384 }
385
386 protected:
387 // Some tests can be configured... here you can find the config settings
388 bool m_bSimpleTellITest; // if true, no SeekI will be used by the TellI test.
389 // Default false.
390 bool m_bSimpleTellOTest; // if true, no SeekO will be used by the TellI test.
391 // Default false.
392 bool m_bSeekInvalidBeyondEnd; // if true a SeekI|O beyond the end of the stream should return wxInvalidOffset
393 // Default true.
394 bool m_bEofAtLastRead; // Does EOF occure at the moment the last byte is read or when read past the last byte.
395 // Default true.
396 protected:
397 TStreamIn &CreateInStream()
398 {
399 if (m_pCurrentIn)
400 {
401 wxFAIL_MSG(_T("Error in test case, the previouse input stream needs to be delete first!"));
402 }
403
404 m_pCurrentIn = DoCreateInStream();
405 wxASSERT(m_pCurrentIn != NULL);
406 return *m_pCurrentIn;
407 }
408 TStreamOut &CreateOutStream()
409 {
410 if (m_pCurrentOut)
411 {
412 wxFAIL_MSG(_T("Error in test case, the previouse output stream needs to be delete first!"));
413 }
414
415 m_pCurrentOut = DoCreateOutStream();
416 wxASSERT(m_pCurrentOut != NULL);
417 return *m_pCurrentOut;
418 }
419
420 void DeleteInStream()
421 {
422 if (m_pCurrentIn == NULL)
423 return;
424 delete m_pCurrentIn;
425 m_pCurrentIn = NULL;
426 // Incase something extra needs to be done.
427 DoDeleteInStream();
428 }
429 void DeleteOutStream()
430 {
431 if (m_pCurrentOut == NULL)
432 return;
433
434 CPPUNIT_ASSERT(m_pCurrentOut->Close());
435
436 delete m_pCurrentOut;
437 m_pCurrentOut = NULL;
438 // Incase something extra needs to be done.
439 DoDeleteOutStream();
440 }
441
442 protected:
443 // Items that need to be implemented by a derived class!
444 virtual TStreamIn *DoCreateInStream() = 0;
445 virtual TStreamOut *DoCreateOutStream() = 0;
446 virtual void DoDeleteInStream() { /* Depends on the base class */ }
447 virtual void DoDeleteOutStream() { /* Depends on the base class */ }
448
449 private:
450 TStreamIn *m_pCurrentIn;
451 TStreamOut *m_pCurrentOut;
452 };
453
454 #endif
455
456