1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: tests/archive/ziptest.cpp
3 // Purpose: Test the zip classes
4 // Author: Mike Wetherell
5 // RCS-ID: $Id: ziptest.cpp 36429 2005-12-18 13:58:55Z MW $
6 // Copyright: (c) 2004 Mike Wetherell
7 // Licence: wxWindows licence
8 ///////////////////////////////////////////////////////////////////////////////
9
10 #include "testprec.h"
11
12 #ifdef __BORLANDC__
13 # pragma hdrstop
14 #endif
15
16 #ifndef WX_PRECOMP
17 # include "wx/wx.h"
18 #endif
19
20 #if wxUSE_STREAMS && wxUSE_ZIPSTREAM
21
22 #include "archivetest.h"
23 #include "wx/zipstrm.h"
24
25 using std::string;
26 using std::auto_ptr;
27
28
29 ///////////////////////////////////////////////////////////////////////////////
30 // ArchiveTestCase<wxZipClassFactory> could be used directly, but instead this
31 // derived class is used so that zip specific features can be tested.
32
33 class ZipTestCase : public ArchiveTestCase<wxZipClassFactory>
34 {
35 public:
ZipTestCase(string name,int options,const wxString & archiver=wxEmptyString,const wxString & unarchiver=wxEmptyString)36 ZipTestCase(string name,
37 int options,
38 const wxString& archiver = wxEmptyString,
39 const wxString& unarchiver = wxEmptyString)
40 :
41 ArchiveTestCase<wxZipClassFactory>(name, new wxZipClassFactory,
42 options, archiver, unarchiver),
43 m_count(0)
44 { }
45
46 protected:
47 void OnCreateArchive(wxZipOutputStream& zip);
48
49 void OnArchiveExtracted(wxZipInputStream& zip, int expectedTotal);
50
51 void OnCreateEntry(wxZipOutputStream& zip,
52 TestEntry& testEntry,
53 wxZipEntry *entry);
54
55 void OnEntryExtracted(wxZipEntry& entry,
56 const TestEntry& testEntry,
57 wxZipInputStream *arc);
58
59 void OnSetNotifier(EntryT& entry);
60
61 int m_count;
62 wxString m_comment;
63 };
64
OnCreateArchive(wxZipOutputStream & zip)65 void ZipTestCase::OnCreateArchive(wxZipOutputStream& zip)
66 {
67 m_comment << _T("Comment for test ") << m_id;
68 zip.SetComment(m_comment);
69 }
70
OnArchiveExtracted(wxZipInputStream & zip,int expectedTotal)71 void ZipTestCase::OnArchiveExtracted(wxZipInputStream& zip, int expectedTotal)
72 {
73 CPPUNIT_ASSERT(zip.GetComment() == m_comment);
74 CPPUNIT_ASSERT(zip.GetTotalEntries() == expectedTotal);
75 }
76
OnCreateEntry(wxZipOutputStream & zip,TestEntry & testEntry,wxZipEntry * entry)77 void ZipTestCase::OnCreateEntry(wxZipOutputStream& zip,
78 TestEntry& testEntry,
79 wxZipEntry *entry)
80 {
81 zip.SetLevel((m_id + m_count) % 10);
82
83 if (entry) {
84 switch ((m_id + m_count) % 5) {
85 case 0:
86 {
87 wxString comment = _T("Comment for ") + entry->GetName();
88 entry->SetComment(comment);
89 // lowercase the expected result, and the notifier should do
90 // the same for the zip entries when ModifyArchive() runs
91 testEntry.SetComment(comment.Lower());
92 break;
93 }
94 case 2:
95 entry->SetMethod(wxZIP_METHOD_STORE);
96 break;
97 case 4:
98 entry->SetMethod(wxZIP_METHOD_DEFLATE);
99 break;
100 }
101 entry->SetIsText(testEntry.IsText());
102 }
103
104 m_count++;
105 }
106
OnEntryExtracted(wxZipEntry & entry,const TestEntry & testEntry,wxZipInputStream * arc)107 void ZipTestCase::OnEntryExtracted(wxZipEntry& entry,
108 const TestEntry& testEntry,
109 wxZipInputStream *arc)
110 {
111 // provide some context for the error message so that we know which
112 // iteration of the loop we were on
113 wxString name = _T(" '") + entry.GetName() + _T("'");
114 string error_entry(name.mb_str());
115 string error_context(" failed for entry" + error_entry);
116
117 CPPUNIT_ASSERT_MESSAGE("GetComment" + error_context,
118 entry.GetComment() == testEntry.GetComment());
119
120 // for seekable streams, GetNextEntry() doesn't read the local header so
121 // call OpenEntry() to do it
122 if (arc && (m_options & PipeIn) == 0 && entry.IsDir())
123 arc->OpenEntry(entry);
124
125 CPPUNIT_ASSERT_MESSAGE("IsText" + error_context,
126 entry.IsText() == testEntry.IsText());
127
128 CPPUNIT_ASSERT_MESSAGE("Extra/LocalExtra mismatch for entry" + error_entry,
129 (entry.GetExtraLen() != 0 && entry.GetLocalExtraLen() != 0) ||
130 (entry.GetExtraLen() == 0 && entry.GetLocalExtraLen() == 0));
131 }
132
133 // check the notifier mechanism by using it to fold the entry comments to
134 // lowercase
135 //
136 class ZipNotifier : public wxZipNotifier
137 {
138 public:
139 void OnEntryUpdated(wxZipEntry& entry);
140 };
141
OnEntryUpdated(wxZipEntry & entry)142 void ZipNotifier::OnEntryUpdated(wxZipEntry& entry)
143 {
144 entry.SetComment(entry.GetComment().Lower());
145 }
146
OnSetNotifier(EntryT & entry)147 void ZipTestCase::OnSetNotifier(EntryT& entry)
148 {
149 static ZipNotifier notifier;
150 entry.SetNotifier(notifier);
151 }
152
153
154 ///////////////////////////////////////////////////////////////////////////////
155 // 'zip - -' produces local headers without the size field set. This is a
156 // case not covered by all the other tests, so this class tests it as a
157 // special case
158
159 class ZipPipeTestCase : public CppUnit::TestCase
160 {
161 public:
ZipPipeTestCase(string name,int options)162 ZipPipeTestCase(string name, int options) :
163 CppUnit::TestCase(TestId::MakeId() + name),
164 m_options(options),
165 m_id(TestId::GetId())
166 { }
167
168 protected:
169 void runTest();
170 int m_options;
171 int m_id;
172 };
173
runTest()174 void ZipPipeTestCase::runTest()
175 {
176 TestOutputStream out(m_options);
177
178 wxString testdata = _T("test data to pipe through zip");
179 wxString cmd = _T("echo ") + testdata + _T(" | zip -q - -");
180
181 {
182 PFileInputStream in(cmd);
183 if (in.Ok())
184 out.Write(in);
185 }
186
187 TestInputStream in(out, m_id % ((m_options & PipeIn) ? 4 : 3));
188 wxZipInputStream zip(in);
189
190 auto_ptr<wxZipEntry> entry(zip.GetNextEntry());
191 CPPUNIT_ASSERT(entry.get() != NULL);
192
193 if ((m_options & PipeIn) == 0)
194 CPPUNIT_ASSERT(entry->GetSize() != wxInvalidOffset);
195
196 char buf[64];
197 size_t len = zip.Read(buf, sizeof(buf) - 1).LastRead();
198
199 while (len > 0 && buf[len - 1] <= 32)
200 --len;
201 buf[len] = 0;
202
203 CPPUNIT_ASSERT(zip.Eof());
204 CPPUNIT_ASSERT(wxString(buf, *wxConvCurrent) == testdata);
205 }
206
207
208 ///////////////////////////////////////////////////////////////////////////////
209 // Zip suite
210
211 class ziptest : public ArchiveTestSuite
212 {
213 public:
214 ziptest();
suite()215 static CppUnit::Test *suite() { return (new ziptest)->makeSuite(); }
216
217 protected:
218 ArchiveTestSuite *makeSuite();
219
220 CppUnit::Test *makeTest(string descr, int options,
221 bool genericInterface, const wxString& archiver,
222 const wxString& unarchiver);
223 };
224
ziptest()225 ziptest::ziptest()
226 : ArchiveTestSuite("zip")
227 {
228 AddArchiver(_T("zip -qr %s *"));
229 AddUnArchiver(_T("unzip -q %s"));
230 }
231
makeSuite()232 ArchiveTestSuite *ziptest::makeSuite()
233 {
234 ArchiveTestSuite::makeSuite();
235
236 #ifndef WXARC_NO_POPEN
237 // if have popen then can check the piped output of 'zip - -'
238 if (IsInPath(_T("zip")))
239 for (int options = 0; options <= PipeIn; options += PipeIn) {
240 string name = Description(_T("ZipPipeTestCase"), options,
241 false, _T(""), _T("zip -q - -"));
242 addTest(new ZipPipeTestCase(name, options));
243 }
244 #endif
245
246 return this;
247 }
248
makeTest(string descr,int options,bool genericInterface,const wxString & archiver,const wxString & unarchiver)249 CppUnit::Test *ziptest::makeTest(
250 string descr,
251 int options,
252 bool genericInterface,
253 const wxString& archiver,
254 const wxString& unarchiver)
255 {
256 // unzip doesn't support piping in the zip
257 if ((options & PipeIn) && !unarchiver.empty())
258 return NULL;
259
260 if (genericInterface)
261 return new ArchiveTestCase<wxArchiveClassFactory>(
262 descr, new wxZipClassFactory,
263 options, archiver, unarchiver);
264 else
265 return new ZipTestCase(descr, options, archiver, unarchiver);
266 }
267
268 CPPUNIT_TEST_SUITE_REGISTRATION(ziptest);
269 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(ziptest, "archive");
270 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(ziptest, "archive/zip");
271
272 #endif // wxUSE_STREAMS && wxUSE_ZIPSTREAM
273