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