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: bstream.h 30731 2004-11-23 14:26:10Z RN $
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:
CleanupHelper(StreamTestCase * value)44         CleanupHelper(StreamTestCase *value)
45             :m_pCleanup(value)
46         {}
~CleanupHelper()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:
BaseStreamTestCase()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 */ }
~BaseStreamTestCase()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.
Input_GetSize()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.
Input_GetC()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.
Input_Read()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.
Input_Eof()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.
Input_LastRead()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     // Just try to perform a SeekI() on the input stream.
Input_SeekI()179     void Input_SeekI()
180     {
181         CleanupHelper cleanup(this);
182         TStreamIn &stream_in = CreateInStream();
183         CPPUNIT_ASSERT(!stream_in.Eof());
184 
185         // Try to Seek in the stream...
186         // Note: streams not supporting this should register this test
187         //       with CPPUNIT_TEST_FAIL instead of CPPUNIT_TEST.
188         CPPUNIT_ASSERT(stream_in.SeekI(2, wxFromStart) == 2);
189         CPPUNIT_ASSERT(stream_in.SeekI(2, wxFromCurrent) == 4);
190         // Not sure the following line is correct, so test it differently.
191         //CPPUNIT_ASSERT(stream_in.SeekI(-2, wxFromEnd) == (off_t)stream_in.GetSize()-2);
192         CPPUNIT_ASSERT(stream_in.SeekI(-2, wxFromEnd) != wxInvalidOffset);
193         // Go beyond the stream size.
194         CPPUNIT_ASSERT((stream_in.SeekI(10, wxFromCurrent) == wxInvalidOffset) == m_bSeekInvalidBeyondEnd);
195     }
196 
197     // Just try to perform a TellI() on the input stream.
Input_TellI()198     void Input_TellI()
199     {
200         CleanupHelper cleanup(this);
201         TStreamIn &stream_in = CreateInStream();
202         CPPUNIT_ASSERT(!stream_in.Eof());
203 
204         // Try to Get the location in the stream...
205         CPPUNIT_ASSERT(stream_in.TellI() == 0);
206         (void)stream_in.GetC();
207         CPPUNIT_ASSERT(stream_in.TellI() == 1);
208         if (!m_bSimpleTellITest)
209         {
210             wxFileOffset pos = stream_in.SeekI(5, wxFromStart);
211             CPPUNIT_ASSERT(stream_in.TellI() == pos);
212             (void)stream_in.GetC();
213             CPPUNIT_ASSERT(stream_in.TellI() == 6);
214             pos = stream_in.SeekI(2, wxFromCurrent);
215             CPPUNIT_ASSERT(stream_in.TellI() == pos);
216             pos = stream_in.SeekI(5, wxFromStart);
217             CPPUNIT_ASSERT(stream_in.TellI() == pos);
218         }
219     }
220 
221     // Just try to perform a Peek() on the input stream.
Input_Peek()222     void Input_Peek()
223     {
224         CleanupHelper cleanup(this);
225         TStreamIn &stream_in = CreateInStream();
226 
227         // Test the full stream
228         while (stream_in.IsOk())
229         {
230             char peekChar = stream_in.Peek();
231             char getChar = stream_in.GetC();
232             if (stream_in.LastRead() == 1)
233                 CPPUNIT_ASSERT(peekChar == getChar);
234         }
235     }
236 
237     // Just try to perform a Ungetch() on the input stream.
Input_Ungetch()238     void Input_Ungetch()
239     {
240         CleanupHelper cleanup(this);
241         TStreamIn &stream_in = CreateInStream();
242         CPPUNIT_ASSERT(!stream_in.Eof());
243 
244         const char *ungetstr = "test";
245         size_t ungetsize = stream_in.Ungetch(ungetstr, strlen(ungetstr) + 1);
246         if (ungetsize != 0)
247         {
248             CPPUNIT_ASSERT(ungetsize == strlen(ungetstr) + 1);
249             char buf[10];
250             (void)stream_in.Read(buf, ungetsize);
251             CPPUNIT_ASSERT(strcmp(buf, ungetstr) == 0);
252         }
253 
254         if (stream_in.Ungetch('a'))
255         {
256             CPPUNIT_ASSERT(stream_in.GetC() == 'a');
257         }
258     }
259 
260     /*
261      * Output stream tests.
262      */
263 
264     // Just try to perform a PutC() on the output stream.
Output_PutC()265     void Output_PutC()
266     {
267         CleanupHelper cleanup(this);
268         TStreamOut &stream_out = CreateOutStream();
269 
270         char *buf = "Some text";
271         int i;
272         int len = strlen(buf);
273         for (i = 0; i < len; i++)
274             stream_out.PutC(buf[i]);
275 
276         CPPUNIT_ASSERT(i == stream_out.TellO());
277     }
278 
279     // Just try to perform a Write() on the output stream.
Output_Write()280     void Output_Write()
281     {
282         CleanupHelper cleanup(this);
283         TStreamOut &stream_out = CreateOutStream();
284 
285         // Do the buffer version.
286         char *buf = "Some text";
287         int len = strlen(buf);
288         (void)stream_out.Write(buf, len);
289         CPPUNIT_ASSERT(stream_out.TellO() == len);
290 
291         // Do the Stream version.
292         TStreamIn &stream_in = CreateInStream();
293         (void)stream_out.Write(stream_in);
294         CPPUNIT_ASSERT(stream_out.TellO() > len);
295     }
296 
297     // Just try to perform a LastWrite() on the output stream.
Output_LastWrite()298     void Output_LastWrite()
299     {
300         CleanupHelper cleanup(this);
301         TStreamOut &stream_out = CreateOutStream();
302 
303         char *buf = "12345";
304         (void)stream_out.Write(buf, 5);
305         CPPUNIT_ASSERT(stream_out.LastWrite() == 5);
306         (void)stream_out.PutC('1');
307         CPPUNIT_ASSERT(stream_out.LastWrite() == 1);
308     }
309 
310     // Just try to perform a SeekO() on the output stream.
Output_SeekO()311     void Output_SeekO()
312     {
313         CleanupHelper cleanup(this);
314         TStreamOut &stream_out = CreateOutStream();
315 
316         // First put some data in the stream, so it is not empty.
317         char *buf = "1234567890";
318         (void)stream_out.Write(buf, 10);
319 
320         // Try to Seek in the stream...
321         // Note: streams not supporting this should register this test
322         //       with CPPUNIT_TEST_FAIL instead of CPPUNIT_TEST.
323         CPPUNIT_ASSERT(stream_out.SeekO(2, wxFromStart) == 2);
324         CPPUNIT_ASSERT(stream_out.SeekO(2, wxFromCurrent) == 4);
325         // Not sure the following line is correct, so test it differently.
326         //CPPUNIT_ASSERT(stream_out.SeekO(-2, wxFromEnd) == (off_t)stream_in.GetSize()-2);
327         CPPUNIT_ASSERT(stream_out.SeekO(-2, wxFromEnd) != wxInvalidOffset);
328         // Go beyond the stream size.
329         CPPUNIT_ASSERT((stream_out.SeekO(10, wxFromCurrent) == wxInvalidOffset) == m_bSeekInvalidBeyondEnd);
330     }
331 
332     // Just try to perform a TellO() on the output stream.
Output_TellO()333     void Output_TellO()
334     {
335         CleanupHelper cleanup(this);
336         TStreamOut &stream_out = CreateOutStream();
337 
338         // Try to Get the location in the stream...
339         CPPUNIT_ASSERT(stream_out.TellO() == 0);
340         (void)stream_out.PutC('1');
341         CPPUNIT_ASSERT(stream_out.TellO() == 1);
342         if (!m_bSimpleTellOTest)
343         {
344             // First put some extra data in the stream, so it's not empty.
345             char *buf = "1234567890";
346             (void)stream_out.Write(buf, 10);
347 
348             off_t pos = stream_out.SeekO(5, wxFromStart);
349             CPPUNIT_ASSERT(stream_out.TellO() == pos);
350             (void)stream_out.PutC('1');
351             CPPUNIT_ASSERT(stream_out.TellO() == 6);
352             pos = stream_out.SeekO(2, wxFromCurrent);
353             CPPUNIT_ASSERT(stream_out.TellO() == pos);
354             pos = stream_out.SeekO(5, wxFromStart);
355             CPPUNIT_ASSERT(stream_out.TellO() == pos);
356         }
357     }
358 
359 protected:
360     // Some tests can be configured... here you can find the config settings
361     bool m_bSimpleTellITest;    // if true, no SeekI will be used by the TellI test.
362                                 // Default false.
363     bool m_bSimpleTellOTest;    // if true, no SeekO will be used by the TellI test.
364                                 // Default false.
365     bool m_bSeekInvalidBeyondEnd; // if true a SeekI|O beyond the end of the stream should return wxInvalidOffset
366                                   // Default true.
367     bool m_bEofAtLastRead;      // Does EOF occure at the moment the last byte is read or when read past the last byte.
368                                 // Default true.
369 protected:
CreateInStream()370     TStreamIn &CreateInStream()
371     {
372         if (m_pCurrentIn)
373         {
374             wxFAIL_MSG(_T("Error in test case, the previouse input stream needs to be delete first!"));
375         }
376 
377         m_pCurrentIn = DoCreateInStream();
378         wxASSERT(m_pCurrentIn != NULL);
379         return *m_pCurrentIn;
380     }
CreateOutStream()381     TStreamOut &CreateOutStream()
382     {
383         if (m_pCurrentOut)
384         {
385             wxFAIL_MSG(_T("Error in test case, the previouse output stream needs to be delete first!"));
386         }
387 
388         m_pCurrentOut = DoCreateOutStream();
389         wxASSERT(m_pCurrentOut != NULL);
390         return *m_pCurrentOut;
391     }
392 
DeleteInStream()393     void DeleteInStream()
394     {
395         if (m_pCurrentIn == NULL)
396             return;
397         delete m_pCurrentIn;
398         m_pCurrentIn = NULL;
399         // Incase something extra needs to be done.
400         DoDeleteInStream();
401     }
DeleteOutStream()402     void DeleteOutStream()
403     {
404         if (m_pCurrentOut == NULL)
405             return;
406 
407         CPPUNIT_ASSERT(m_pCurrentOut->Close());
408 
409         delete m_pCurrentOut;
410         m_pCurrentOut = NULL;
411         // Incase something extra needs to be done.
412         DoDeleteOutStream();
413     }
414 
415 protected:
416     // Items that need to be implemented by a derived class!
417     virtual TStreamIn  *DoCreateInStream() = 0;
418     virtual TStreamOut *DoCreateOutStream() = 0;
DoDeleteInStream()419     virtual void DoDeleteInStream()  { /* Depends on the base class */ }
DoDeleteOutStream()420     virtual void DoDeleteOutStream() { /* Depends on the base class */ }
421 
422 private:
423     TStreamIn  *m_pCurrentIn;
424     TStreamOut *m_pCurrentOut;
425 };
426 
427 #endif
428 
429 
430