stream tests improvements (patch 924438)
[wxWidgets.git] / tests / streams / zlibstream.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: tests/streams/zlibstream.cpp
3 // Purpose: Test wxZlibInputStream/wxZlibOutputStream
4 // Author: Hans Van Leemputten
5 // RCS-ID: $Id$
6 // Copyright: (c) 2004 Hans Van Leemputten
7 // Licence: wxWidgets licence
8 ///////////////////////////////////////////////////////////////////////////////
9
10 #if defined(__GNUG__) && !defined(__APPLE__)
11 #pragma implementation
12 #pragma interface
13 #endif
14
15 // For compilers that support precompilation, includes "wx/wx.h".
16 #include "wx/wxprec.h"
17
18 #ifdef __BORLANDC__
19 #pragma hdrstop
20 #endif
21
22 // for all others, include the necessary headers
23 #ifndef WX_PRECOMP
24 #include "wx/wx.h"
25 #endif
26
27 #include "wx/cppunit.h"
28 #include "wx/zstream.h"
29 #include "wx/wfstream.h"
30 #include "wx/mstream.h"
31
32 #include "bstream.h"
33
34 using namespace std;
35 using namespace CppUnit;
36
37 #define WXTEST_WITH_GZIP_CONDITION(testMethod) \
38 WXTEST_WITH_CONDITION( COMPOSE_TEST_NAME(zlibStream), wxZlibInputStream::CanHandleGZip() && wxZlibOutputStream::CanHandleGZip(), testMethod )
39
40 #define DATABUFFER_SIZE 1024
41
42 static const wxString FILENAME_GZ = _T("zlibtest.gz");
43
44 ///////////////////////////////////////////////////////////////////////////////
45 // The test case
46 //
47 // Try to fully test wxZlibInputStream and wxZlibOutputStream
48
49 class zlibStream : public BaseStreamTestCase<wxZlibInputStream, wxZlibOutputStream>
50 {
51 public:
52 zlibStream();
53 virtual ~zlibStream();
54
55 CPPUNIT_TEST_SUITE(zlibStream);
56 // Base class stream tests the zlibstream supports.
57 CPPUNIT_TEST_FAIL(Input_GetSize);
58 CPPUNIT_TEST(Input_GetC);
59 CPPUNIT_TEST(Input_Read);
60 CPPUNIT_TEST(Input_Eof);
61 CPPUNIT_TEST(Input_LastRead);
62 CPPUNIT_TEST_FAIL(Input_SeekI);
63 CPPUNIT_TEST(Input_TellI);
64 CPPUNIT_TEST(Input_Peek);
65 CPPUNIT_TEST(Input_Ungetch);
66
67 CPPUNIT_TEST(Output_PutC);
68 CPPUNIT_TEST(Output_Write);
69 CPPUNIT_TEST(Output_LastWrite);
70 CPPUNIT_TEST_FAIL(Output_SeekO);
71 CPPUNIT_TEST(Output_TellO);
72
73 // Other test specific for zlib stream test case.
74 CPPUNIT_TEST(TestStream_NoHeader_Default);
75 CPPUNIT_TEST(TestStream_NoHeader_NoComp);
76 CPPUNIT_TEST(TestStream_NoHeader_SpeedComp);
77 CPPUNIT_TEST(TestStream_NoHeader_BestComp);
78 CPPUNIT_TEST(TestStream_ZLib_Default);
79 CPPUNIT_TEST(TestStream_ZLib_NoComp);
80 CPPUNIT_TEST(TestStream_ZLib_SpeedComp);
81 CPPUNIT_TEST(TestStream_ZLib_BestComp);
82 WXTEST_WITH_GZIP_CONDITION(TestStream_GZip_Default);
83 WXTEST_WITH_GZIP_CONDITION(TestStream_GZip_NoComp);
84 WXTEST_WITH_GZIP_CONDITION(TestStream_GZip_SpeedComp);
85 WXTEST_WITH_GZIP_CONDITION(TestStream_GZip_BestComp);
86 WXTEST_WITH_GZIP_CONDITION(TestStream_ZLibGZip);
87 CPPUNIT_TEST(Decompress_BadData);
88 CPPUNIT_TEST(Decompress_wx24Data);
89 CPPUNIT_TEST_SUITE_END();
90
91 protected:
92 // Test different stream construct settings.
93 void TestStream_NoHeader_Default();
94 void TestStream_NoHeader_NoComp();
95 void TestStream_NoHeader_SpeedComp();
96 void TestStream_NoHeader_BestComp();
97 void TestStream_ZLib_Default();
98 void TestStream_ZLib_NoComp();
99 void TestStream_ZLib_SpeedComp();
100 void TestStream_ZLib_BestComp();
101 void TestStream_GZip_Default();
102 void TestStream_GZip_NoComp();
103 void TestStream_GZip_SpeedComp();
104 void TestStream_GZip_BestComp();
105 void TestStream_ZLibGZip();
106 // Try to decompress bad data.
107 void Decompress_BadData();
108 // Decompress a data file created with wx 2.4.
109 // Note: This test is limited in testing range!
110 void Decompress_wx24Data();
111
112 private:
113 const char *GetDataBuffer();
114 const unsigned char *GetCompressedData();
115 void doTestStreamData(int input_flag, int output_flag, int compress_level);
116
117 private:
118 // Implement base class functions.
119 virtual wxZlibInputStream *DoCreateInStream();
120 virtual wxZlibOutputStream *DoCreateOutStream();
121 virtual void DoDeleteInStream();
122 virtual void DoDeleteOutStream();
123
124 private:
125 char m_DataBuffer[DATABUFFER_SIZE];
126 size_t m_SizeCompressedData;
127 unsigned char *m_pCompressedData;
128
129 // Used by the base Creat[In|Out]Stream and Delete[In|Out]Stream.
130 wxMemoryInputStream *m_pTmpMemInStream;
131 wxMemoryOutputStream *m_pTmpMemOutStream;
132 };
133
134 zlibStream::zlibStream()
135 :m_SizeCompressedData(0),
136 m_pCompressedData(NULL),
137 m_pTmpMemInStream(NULL),
138 m_pTmpMemOutStream(NULL)
139 {
140 // Init the data buffer.
141 for (size_t i = 0; i < DATABUFFER_SIZE; i++)
142 m_DataBuffer[i] = (i % 0xFF);
143
144 // Set extra base config settings.
145 m_bSimpleTellITest = true;
146 m_bSimpleTellOTest = true;
147 }
148
149 zlibStream::~zlibStream()
150 {
151 delete m_pCompressedData;
152
153 delete m_pTmpMemInStream;
154 delete m_pTmpMemOutStream;
155 }
156
157 void zlibStream::TestStream_NoHeader_Default()
158 {
159 doTestStreamData(wxZLIB_NO_HEADER, wxZLIB_NO_HEADER, wxZ_DEFAULT_COMPRESSION);
160 }
161 void zlibStream::TestStream_NoHeader_NoComp()
162 {
163 doTestStreamData(wxZLIB_NO_HEADER, wxZLIB_NO_HEADER, wxZ_NO_COMPRESSION);
164 }
165 void zlibStream::TestStream_NoHeader_SpeedComp()
166 {
167 doTestStreamData(wxZLIB_NO_HEADER, wxZLIB_NO_HEADER, wxZ_BEST_SPEED);
168 }
169 void zlibStream::TestStream_NoHeader_BestComp()
170 {
171 doTestStreamData(wxZLIB_NO_HEADER, wxZLIB_NO_HEADER, wxZ_BEST_COMPRESSION);
172 }
173
174 void zlibStream::TestStream_ZLib_Default()
175 {
176 doTestStreamData(wxZLIB_ZLIB, wxZLIB_ZLIB, wxZ_DEFAULT_COMPRESSION);
177 }
178 void zlibStream::TestStream_ZLib_NoComp()
179 {
180 doTestStreamData(wxZLIB_ZLIB, wxZLIB_ZLIB, wxZ_NO_COMPRESSION);
181 }
182 void zlibStream::TestStream_ZLib_SpeedComp()
183 {
184 doTestStreamData(wxZLIB_ZLIB, wxZLIB_ZLIB, wxZ_BEST_SPEED);
185 }
186 void zlibStream::TestStream_ZLib_BestComp()
187 {
188 doTestStreamData(wxZLIB_ZLIB, wxZLIB_ZLIB, wxZ_BEST_COMPRESSION);
189 }
190
191 void zlibStream::TestStream_GZip_Default()
192 {
193 doTestStreamData(wxZLIB_GZIP, wxZLIB_GZIP, wxZ_DEFAULT_COMPRESSION);
194 }
195 void zlibStream::TestStream_GZip_NoComp()
196 {
197 doTestStreamData(wxZLIB_GZIP, wxZLIB_GZIP, wxZ_NO_COMPRESSION);
198 }
199 void zlibStream::TestStream_GZip_SpeedComp()
200 {
201 doTestStreamData(wxZLIB_GZIP, wxZLIB_GZIP, wxZ_BEST_SPEED);
202 }
203 void zlibStream::TestStream_GZip_BestComp()
204 {
205 doTestStreamData(wxZLIB_GZIP, wxZLIB_GZIP, wxZ_BEST_COMPRESSION);
206 }
207
208 void zlibStream::TestStream_ZLibGZip()
209 {
210 // Only use default compression level, as this test is
211 // for testing if the streams can determine the stream type info them self...
212 doTestStreamData(wxZLIB_ZLIB|wxZLIB_GZIP, wxZLIB_ZLIB, wxZ_DEFAULT_COMPRESSION);
213 doTestStreamData(wxZLIB_ZLIB|wxZLIB_GZIP, wxZLIB_GZIP, wxZ_DEFAULT_COMPRESSION);
214 }
215
216 void zlibStream::Decompress_BadData()
217 {
218 // Setup the bad data stream and the zlib stream.
219 wxMemoryInputStream memstream_in(GetDataBuffer(), DATABUFFER_SIZE);
220 CPPUNIT_ASSERT(memstream_in.IsOk());
221 wxZlibInputStream zstream_in(memstream_in);
222 CPPUNIT_ASSERT(zstream_in.IsOk()); // We did not yet read from the stream
223 // so it should still be OK.
224 // Try to force the stream to go to bad status.
225 CPPUNIT_ASSERT(!zstream_in.Eof());
226 if (zstream_in.IsOk())
227 zstream_in.GetC();
228
229 // Because of the bad data in the input stream the zlib
230 // stream should be marked as NOT OK.
231 CPPUNIT_ASSERT(!zstream_in.IsOk());
232 }
233
234 void zlibStream::Decompress_wx24Data()
235 {
236 // The wx24_value was used in a wxWidgets 2.4(.2)
237 // application to produce wx24_data, using wxZlibOutputStream.
238 const unsigned char wx24_data[] = {120,156,242,72,205,201,201,87,40,207,47,202,73,97,0,0,0,0,255,255,0};
239 const char *wx24_value = "Hello world";
240 // Size of the value and date items.
241 const size_t data_size = sizeof(wx24_data);
242 const size_t value_size = strlen(wx24_value);
243
244 const unsigned char *buf = GetCompressedData();
245 m_pTmpMemInStream = new wxMemoryInputStream(buf, m_SizeCompressedData);
246
247 wxMemoryInputStream memstream_in(wx24_data, data_size);
248 CPPUNIT_ASSERT(memstream_in.IsOk());
249 wxZlibInputStream zstream_in(memstream_in);
250 CPPUNIT_ASSERT(zstream_in.IsOk());
251
252 size_t i;
253 for (i = 0; !zstream_in.Eof(); i++)
254 {
255 char last_value = zstream_in.GetC();
256 if (last_value != wx24_value[i])
257 break;
258
259 // Don't go over the end of the value buffer...
260 if (wx24_value[i] == '\0')
261 {
262 // And if we do then try to see how long the stream actually is.
263 for (/* nothing */; !zstream_in.Eof(); i++)
264 {
265 // Move one item along in the stream.
266 (void)zstream_in.GetC();
267
268 // Check if we are in an infinite loop by multiplying value_size
269 // by 5 to have a *much* bigger range then the real range.
270 // Note: Incase you ask your self, why 5, the answer is no reason...
271 // it is not to big and not to small a size, nothing more
272 // nothing less to it.
273 if (i > (value_size*5))
274 {
275 // Note: Please make sure Input_Eof test passed.
276 CPPUNIT_FAIL("Infinite stream detected, breaking the infinite loop");
277 return;
278 }
279 }
280
281 break;
282 }
283 }
284
285 CPPUNIT_ASSERT_MESSAGE("Could not decompress data that was compressed with wxWidgets 2.4.x", i == (value_size + 1));
286 }
287
288 const char *zlibStream::GetDataBuffer()
289 {
290 return m_DataBuffer;
291 }
292
293 const unsigned char *zlibStream::GetCompressedData()
294 {
295 if (!m_pCompressedData)
296 {
297 #if 1
298 // Construct the compressed data live.
299 wxMemoryOutputStream memstream_out;
300 {
301 const char *buf = "01234567890123456789012345678901234567890123456789"; /* = 50 */
302 wxZlibOutputStream zstream_out(memstream_out);
303 zstream_out.Write(buf, strlen(buf));
304 }
305
306 // Copy the to the
307 m_SizeCompressedData = memstream_out.GetSize();
308 m_pCompressedData = new unsigned char[m_SizeCompressedData];
309 memstream_out.CopyTo(m_pCompressedData, m_SizeCompressedData);
310 #else
311 // Or use recorded compressed data.
312 const unsigned char tmp[] = {120,218,51,48,52,50,54,49,53,51,183,176,52,32,142,197,0,0,3,229,10,9,0};
313 m_SizeCompressedData = sizeof(tmp);
314 m_pCompressedData = new unsigned char[m_SizeCompressedData+1];
315 memcpy(m_pCompressedData, tmp, m_SizeCompressedData);
316 #endif
317 }
318
319 CPPUNIT_ASSERT(m_pCompressedData != NULL);
320 return m_pCompressedData;
321 }
322
323 void zlibStream::doTestStreamData(int input_flag, int output_flag, int compress_level)
324 {
325 size_t fail_pos = 0;
326 char last_value = 0;
327 bool bWasEOF = true;
328
329 { // Part one: Create a compressed file.
330 wxFileOutputStream fstream_out(FILENAME_GZ);
331 CPPUNIT_ASSERT(fstream_out.IsOk());
332 wxZlibOutputStream zstream_out(fstream_out, compress_level, output_flag);
333 if (!zstream_out.IsOk())
334 {
335 if (output_flag == wxZLIB_GZIP)
336 CPPUNIT_FAIL("Could not create the gzip output stream. Note: gzip requires zlib 1.2+!");
337 else
338 CPPUNIT_FAIL("Could not create the output stream");
339 }
340
341 // Next: Compress some data so the file is containing something.
342 zstream_out.Write(GetDataBuffer(), DATABUFFER_SIZE);
343 }
344
345 { // Part two: Verify that the compressed data when uncompressed
346 // matches the original data.
347 wxFileInputStream fstream_in(FILENAME_GZ);
348 CPPUNIT_ASSERT(fstream_in.IsOk());
349 wxZlibInputStream zstream_in(fstream_in, input_flag);
350 CPPUNIT_ASSERT_MESSAGE("Could not create the input stream", zstream_in.IsOk());
351
352 // Next: Check char per char if the returned data is valid.
353 const char *pbuf = GetDataBuffer();
354 for (fail_pos = 0; !zstream_in.Eof(); fail_pos++)
355 {
356 last_value = zstream_in.GetC();
357 if (last_value != pbuf[fail_pos])
358 break;
359 }
360
361 bWasEOF = zstream_in.Eof();
362 }
363
364 // Remove the temp file...
365 ::wxRemoveFile(FILENAME_GZ);
366
367 // Check state of the verify action.
368 if (fail_pos != DATABUFFER_SIZE || !bWasEOF)
369 {
370 wxString msg(wxString::Format(_T("Wrong data item at pos %d (Org_val %d != Zlib_val %d), with compression level %d"),
371 fail_pos, GetDataBuffer()[fail_pos], last_value, compress_level));
372 CPPUNIT_FAIL(string(msg.mb_str()));
373 }
374 }
375
376 wxZlibInputStream *zlibStream::DoCreateInStream()
377 {
378 const unsigned char *buf = GetCompressedData();
379 m_pTmpMemInStream = new wxMemoryInputStream(buf, m_SizeCompressedData);
380 CPPUNIT_ASSERT(m_pTmpMemInStream->IsOk());
381 wxZlibInputStream *pzstream_in = new wxZlibInputStream(*m_pTmpMemInStream);
382 CPPUNIT_ASSERT(pzstream_in->IsOk());
383 return pzstream_in;
384 }
385 wxZlibOutputStream *zlibStream::DoCreateOutStream()
386 {
387 m_pTmpMemOutStream = new wxMemoryOutputStream();
388 CPPUNIT_ASSERT(m_pTmpMemOutStream->IsOk());
389 wxZlibOutputStream *pzstream_out = new wxZlibOutputStream(*m_pTmpMemOutStream);
390 CPPUNIT_ASSERT(pzstream_out->IsOk());
391 return pzstream_out;
392 }
393 void zlibStream::DoDeleteInStream()
394 {
395 delete m_pTmpMemInStream;
396 m_pTmpMemInStream = NULL;
397 }
398 void zlibStream::DoDeleteOutStream()
399 {
400 delete m_pTmpMemOutStream;
401 m_pTmpMemOutStream = NULL;
402 }
403
404 // Register the stream sub suite, by using some stream helper macro.
405 // Note: Don't forget to connect it to the base suite (See: bstream.cpp => StreamCase::suite())
406 STREAM_TEST_SUBSUITE_NAMED_REGISTRATION(zlibStream)
407