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