]>
Commit | Line | Data |
---|---|---|
e6477b92 MW |
1 | /////////////////////////////////////////////////////////////////////////////// |
2 | // Name: tests/archive/ziptest.cpp | |
3 | // Purpose: Test the zip classes | |
4 | // Author: Mike Wetherell | |
5 | // RCS-ID: $Id$ | |
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: | |
36 | ZipTestCase(string name, | |
e6477b92 MW |
37 | int options, |
38 | const wxString& archiver = wxEmptyString, | |
39 | const wxString& unarchiver = wxEmptyString) | |
40 | : | |
716e748b | 41 | ArchiveTestCase<wxZipClassFactory>(name, new wxZipClassFactory, |
e6477b92 MW |
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 | ||
65 | void ZipTestCase::OnCreateArchive(wxZipOutputStream& zip) | |
66 | { | |
9a83f860 | 67 | m_comment << wxT("Comment for test ") << m_id; |
e6477b92 MW |
68 | zip.SetComment(m_comment); |
69 | } | |
70 | ||
71 | void ZipTestCase::OnArchiveExtracted(wxZipInputStream& zip, int expectedTotal) | |
72 | { | |
73 | CPPUNIT_ASSERT(zip.GetComment() == m_comment); | |
74 | CPPUNIT_ASSERT(zip.GetTotalEntries() == expectedTotal); | |
75 | } | |
76 | ||
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 | { | |
9a83f860 | 87 | wxString comment = wxT("Comment for ") + entry->GetName(); |
e6477b92 MW |
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 | ||
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 | |
9a83f860 | 113 | wxString name = wxT(" '") + entry.GetName() + wxT("'"); |
e6477b92 MW |
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 | ||
142 | void ZipNotifier::OnEntryUpdated(wxZipEntry& entry) | |
143 | { | |
144 | entry.SetComment(entry.GetComment().Lower()); | |
145 | } | |
146 | ||
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: | |
162 | ZipPipeTestCase(string name, int options) : | |
716e748b MW |
163 | CppUnit::TestCase(TestId::MakeId() + name), |
164 | m_options(options), | |
165 | m_id(TestId::GetId()) | |
166 | { } | |
e6477b92 MW |
167 | |
168 | protected: | |
169 | void runTest(); | |
170 | int m_options; | |
716e748b | 171 | int m_id; |
e6477b92 MW |
172 | }; |
173 | ||
174 | void ZipPipeTestCase::runTest() | |
175 | { | |
176 | TestOutputStream out(m_options); | |
177 | ||
9a83f860 VZ |
178 | wxString testdata = wxT("test data to pipe through zip"); |
179 | wxString cmd = wxT("echo ") + testdata + wxT(" | zip -q - -"); | |
e6477b92 MW |
180 | |
181 | { | |
182 | PFileInputStream in(cmd); | |
183 | if (in.Ok()) | |
184 | out.Write(in); | |
185 | } | |
186 | ||
716e748b | 187 | TestInputStream in(out, m_id % ((m_options & PipeIn) ? 4 : 3)); |
e6477b92 MW |
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(); | |
215 | static CppUnit::Test *suite() { return (new ziptest)->makeSuite(); } | |
216 | ||
217 | protected: | |
218 | ArchiveTestSuite *makeSuite(); | |
219 | ||
716e748b | 220 | CppUnit::Test *makeTest(string descr, int options, |
e6477b92 MW |
221 | bool genericInterface, const wxString& archiver, |
222 | const wxString& unarchiver); | |
223 | }; | |
224 | ||
225 | ziptest::ziptest() | |
226 | : ArchiveTestSuite("zip") | |
227 | { | |
9a83f860 VZ |
228 | AddArchiver(wxT("zip -qr %s *")); |
229 | AddUnArchiver(wxT("unzip -q %s")); | |
e6477b92 MW |
230 | } |
231 | ||
232 | ArchiveTestSuite *ziptest::makeSuite() | |
233 | { | |
234 | ArchiveTestSuite::makeSuite(); | |
235 | ||
cc90c1cc MW |
236 | #if !defined WXARC_NO_POPEN && !defined __WXMSW__ |
237 | // If have popen then can check the piped output of 'zip - -'. | |
238 | // The gnuwin32 build of infozip does work for this, e.g.: | |
239 | // C:\>echo test data to pipe through zip | zip -q > foo.zip | |
240 | // doesn't produce a valid zip, so disabled for now. | |
9a83f860 | 241 | if (IsInPath(wxT("zip"))) |
e6477b92 | 242 | for (int options = 0; options <= PipeIn; options += PipeIn) { |
9a83f860 VZ |
243 | string name = Description(wxT("ZipPipeTestCase"), options, |
244 | false, wxT(""), wxT("zip -q - -")); | |
e6477b92 | 245 | addTest(new ZipPipeTestCase(name, options)); |
e6477b92 MW |
246 | } |
247 | #endif | |
248 | ||
249 | return this; | |
250 | } | |
251 | ||
252 | CppUnit::Test *ziptest::makeTest( | |
253 | string descr, | |
e6477b92 MW |
254 | int options, |
255 | bool genericInterface, | |
256 | const wxString& archiver, | |
257 | const wxString& unarchiver) | |
258 | { | |
259 | // unzip doesn't support piping in the zip | |
260 | if ((options & PipeIn) && !unarchiver.empty()) | |
261 | return NULL; | |
262 | ||
263 | if (genericInterface) | |
895cae46 | 264 | { |
e6477b92 | 265 | return new ArchiveTestCase<wxArchiveClassFactory>( |
716e748b | 266 | descr, new wxZipClassFactory, |
e6477b92 | 267 | options, archiver, unarchiver); |
895cae46 VZ |
268 | } |
269 | ||
270 | return new ZipTestCase(descr, options, archiver, unarchiver); | |
e6477b92 MW |
271 | } |
272 | ||
273 | CPPUNIT_TEST_SUITE_REGISTRATION(ziptest); | |
274 | CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(ziptest, "archive"); | |
275 | CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(ziptest, "archive/zip"); | |
276 | ||
277 | #endif // wxUSE_STREAMS && wxUSE_ZIPSTREAM |