bstream.h 15 KB

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