1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: tests/archive/archive.cpp
3 // Purpose: Test the archive classes
4 // Author: Mike Wetherell
6 // Copyright: (c) 2004 Mike Wetherell
7 // Licence: wxWindows licence
8 ///////////////////////////////////////////////////////////////////////////////
22 #define WX_TEST_ARCHIVE_ITERATOR
24 // VC++ 6 warns that the list iterator's '->' operator will not work whenever
25 // std::list is used with a non-pointer, so switch it off.
26 #if defined _MSC_VER && _MSC_VER < 1300
27 #pragma warning (disable:4284)
30 #include "wx/zipstrm.h"
31 #include "wx/mstream.h"
32 #include "wx/wfstream.h"
43 // Check whether member templates can be used
45 #if defined __GNUC__ && \
46 (__GNUC__ >= 3 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95))
47 # define WXARC_MEMBER_TEMPLATES
49 #if defined _MSC_VER && _MSC_VER >= 1310
50 # define WXARC_MEMBER_TEMPLATES
52 #if defined __BORLANDC__ && __BORLANDC__ >= 0x530
53 # define WXARC_MEMBER_TEMPLATES
55 #if defined __DMC__ && __DMC__ >= 0x832
56 # define WXARC_MEMBER_TEMPLATES
58 #if defined __MWERKS__ && __MWERKS__ >= 0x2200
59 # define WXARC_MEMBER_TEMPLATES
61 #if defined __HP_aCC && __HP_aCC > 33300
62 # define WXARC_MEMBER_TEMPLATES
64 #if defined __SUNPRO_CC && __SUNPRO_CC > 0x500
65 # define WXARC_MEMBER_TEMPLATES
69 ///////////////////////////////////////////////////////////////////////////////
70 // Bit flags for options for the tests
74 PipeIn
= 0x01, // input streams are non-seekable
75 PipeOut
= 0x02, // output streams are non-seekable
76 Stub
= 0x04, // the archive should be appended to a stub
81 ///////////////////////////////////////////////////////////////////////////////
82 // These structs are passed as the template parameter of the test case to
83 // specify a set of classes to use in the test. This allows either the generic
84 // wxArchiveXXX interface to be exercised or the specific interface for a
85 // particular archive format e.g. wxZipXXX.
89 typedef wxArchiveEntry EntryT
;
90 typedef wxArchiveInputStream InputStreamT
;
91 typedef wxArchiveOutputStream OutputStreamT
;
92 typedef wxArchiveClassFactory ClassFactoryT
;
93 typedef wxArchiveNotifier NotifierT
;
94 typedef wxArchiveIter IterT
;
95 typedef wxArchivePairIter PairIterT
;
100 typedef wxZipEntry EntryT
;
101 typedef wxZipInputStream InputStreamT
;
102 typedef wxZipOutputStream OutputStreamT
;
103 typedef wxZipClassFactory ClassFactoryT
;
104 typedef wxZipNotifier NotifierT
;
105 typedef wxZipIter IterT
;
106 typedef wxZipPairIter PairIterT
;
110 ///////////////////////////////////////////////////////////////////////////////
111 // A class to hold a test entry
116 TestEntry(const wxDateTime
& dt
, int len
, const char *data
);
117 ~TestEntry() { delete [] m_data
; }
119 wxDateTime
GetDateTime() const { return m_dt
; }
120 wxFileOffset
GetLength() const { return m_len
; }
121 size_t GetSize() const { return m_len
; }
122 const char *GetData() const { return m_data
; }
123 wxString
GetComment() const { return m_comment
; }
124 bool IsText() const { return m_isText
; }
126 void SetComment(const wxString
& comment
) { m_comment
= comment
; }
127 void SetDateTime(const wxDateTime
& dt
) { m_dt
= dt
; }
137 TestEntry::TestEntry(const wxDateTime
& dt
, int len
, const char *data
)
142 m_data
= new char[len
];
143 memcpy(m_data
, data
, len
);
145 for (int i
= 0; i
< len
&& m_isText
; i
++)
146 m_isText
= (signed char)m_data
[i
] > 0;
150 ///////////////////////////////////////////////////////////////////////////////
151 // TestOutputStream and TestInputStream are memory streams which can be
152 // seekable or non-seekable.
154 class TestOutputStream
: public wxOutputStream
157 TestOutputStream(int options
);
159 ~TestOutputStream() { delete [] m_data
; }
161 int GetOptions() const { return m_options
; }
162 wxFileOffset
GetLength() const { return m_size
; }
164 // gives away the data, this stream is then empty, and can be reused
165 void GetData(char*& data
, size_t& size
);
167 enum { STUB_SIZE
= 2048, INITIAL_SIZE
= 0x18000, SEEK_LIMIT
= 0x100000 };
172 wxFileOffset
OnSysSeek(wxFileOffset pos
, wxSeekMode mode
);
173 wxFileOffset
OnSysTell() const;
174 size_t OnSysWrite(const void *buffer
, size_t size
);
183 TestOutputStream::TestOutputStream(int options
)
189 void TestOutputStream::Init()
196 if (m_options
& Stub
) {
197 wxCharBuffer
buf(STUB_SIZE
);
198 memset(buf
.data(), 0, STUB_SIZE
);
199 Write(buf
, STUB_SIZE
);
203 wxFileOffset
TestOutputStream::OnSysSeek(wxFileOffset pos
, wxSeekMode mode
)
205 if ((m_options
& PipeOut
) == 0) {
207 case wxFromStart
: break;
208 case wxFromCurrent
: pos
+= m_pos
; break;
209 case wxFromEnd
: pos
+= m_size
; break;
211 if (pos
< 0 || pos
> SEEK_LIMIT
)
212 return wxInvalidOffset
;
216 return wxInvalidOffset
;
219 wxFileOffset
TestOutputStream::OnSysTell() const
221 return (m_options
& PipeOut
) == 0 ? (wxFileOffset
)m_pos
: wxInvalidOffset
;
224 size_t TestOutputStream::OnSysWrite(const void *buffer
, size_t size
)
226 if (!IsOk() || !size
)
228 m_lasterror
= wxSTREAM_WRITE_ERROR
;
230 size_t newsize
= m_pos
+ size
;
231 wxCHECK(newsize
> m_pos
, 0);
233 if (m_capacity
< newsize
) {
234 size_t capacity
= m_capacity
? m_capacity
: INITIAL_SIZE
;
236 while (capacity
< newsize
) {
238 wxCHECK(capacity
> m_capacity
, 0);
241 char *buf
= new char[capacity
];
243 memcpy(buf
, m_data
, m_capacity
);
246 m_capacity
= capacity
;
249 memcpy(m_data
+ m_pos
, buffer
, size
);
253 m_lasterror
= wxSTREAM_NO_ERROR
;
258 void TestOutputStream::GetData(char*& data
, size_t& size
)
263 if (m_options
& Stub
) {
267 if (size
> m_capacity
) {
269 memcpy(d
+ STUB_SIZE
, m_data
, m_size
);
273 memmove(d
+ STUB_SIZE
, d
, m_size
);
276 memset(d
, 0, STUB_SIZE
);
284 class TestInputStream
: public wxInputStream
287 // ctor takes the data from the output stream, which is then empty
288 TestInputStream(TestOutputStream
& out
) : m_data(NULL
) { SetData(out
); }
290 TestInputStream(const TestInputStream
& in
);
291 ~TestInputStream() { delete [] m_data
; }
294 wxFileOffset
GetLength() const { return m_size
; }
295 void SetData(TestOutputStream
& out
);
298 wxFileOffset
OnSysSeek(wxFileOffset pos
, wxSeekMode mode
);
299 wxFileOffset
OnSysTell() const;
300 size_t OnSysRead(void *buffer
, size_t size
);
308 TestInputStream::TestInputStream(const TestInputStream
& in
)
309 : m_options(in
.m_options
),
313 m_data
= new char[m_size
];
314 memcpy(m_data
, in
.m_data
, m_size
);
317 void TestInputStream::Rewind()
319 if ((m_options
& Stub
) && (m_options
& PipeIn
))
320 m_pos
= TestOutputStream::STUB_SIZE
* 2;
332 void TestInputStream::SetData(TestOutputStream
& out
)
335 m_options
= out
.GetOptions();
336 out
.GetData(m_data
, m_size
);
341 wxFileOffset
TestInputStream::OnSysSeek(wxFileOffset pos
, wxSeekMode mode
)
343 if ((m_options
& PipeIn
) == 0) {
345 case wxFromStart
: break;
346 case wxFromCurrent
: pos
+= m_pos
; break;
347 case wxFromEnd
: pos
+= m_size
; break;
349 if (pos
< 0 || pos
> TestOutputStream::SEEK_LIMIT
)
350 return wxInvalidOffset
;
354 return wxInvalidOffset
;
357 wxFileOffset
TestInputStream::OnSysTell() const
359 return (m_options
& PipeIn
) == 0 ? (wxFileOffset
)m_pos
: wxInvalidOffset
;
362 size_t TestInputStream::OnSysRead(void *buffer
, size_t size
)
364 if (!IsOk() || !size
)
366 if (m_size
<= m_pos
) {
367 m_lasterror
= wxSTREAM_EOF
;
371 if (m_size
- m_pos
< size
)
372 size
= m_size
- m_pos
;
373 memcpy(buffer
, m_data
+ m_pos
, size
);
379 ///////////////////////////////////////////////////////////////////////////////
380 // minimal non-intrusive reference counting pointer for testing the iterators
382 template <class T
> class Ptr
385 explicit Ptr(T
* p
= NULL
) : m_p(p
), m_count(new int) { *m_count
= 1; }
386 Ptr(const Ptr
& sp
) : m_p(sp
.m_p
), m_count(sp
.m_count
) { ++*m_count
; }
389 Ptr
& operator =(const Ptr
& sp
) {
393 m_count
= sp
.m_count
;
399 T
* get() const { return m_p
; }
400 T
* operator->() const { return m_p
; }
401 T
& operator*() const { return *m_p
; }
405 if (--*m_count
== 0) {
416 ///////////////////////////////////////////////////////////////////////////////
417 // Clean-up for temp directory
424 wxString
GetName() const { return m_tmp
; }
427 void RemoveDir(wxString
& path
);
434 wxString tmp
= wxFileName::CreateTempFileName(_T("arctest-"));
435 if (tmp
!= wxEmptyString
) {
437 m_original
= wxGetCwd();
438 CPPUNIT_ASSERT(wxMkdir(tmp
, 0700));
440 CPPUNIT_ASSERT(wxSetWorkingDirectory(tmp
));
446 if (m_tmp
!= wxEmptyString
) {
447 wxSetWorkingDirectory(m_original
);
452 void TempDir::RemoveDir(wxString
& path
)
454 wxCHECK_RET(!m_tmp
.empty() && path
.substr(0, m_tmp
.length()) == m_tmp
,
455 _T("remove '") + path
+ _T("' fails safety check"));
457 const wxChar
*files
[] = {
467 _T("zero/zero32768"),
468 _T("zero/zero16385"),
473 const wxChar
*dirs
[] = {
474 _T("text/"), _T("bin/"), _T("zero/"), _T("empty/")
477 wxString tmp
= m_tmp
+ wxFileName::GetPathSeparator();
480 for (i
= 0; i
< WXSIZEOF(files
); i
++)
481 wxRemoveFile(tmp
+ wxFileName(files
[i
], wxPATH_UNIX
).GetFullPath());
483 for (i
= 0; i
< WXSIZEOF(dirs
); i
++)
484 wxRmdir(tmp
+ wxFileName(dirs
[i
], wxPATH_UNIX
).GetFullPath());
487 wxLogSysError(_T("can't remove temporary dir '%s'"), m_tmp
.c_str());
491 ///////////////////////////////////////////////////////////////////////////////
492 // wxFFile streams for piping to/from an external program
494 #if defined __UNIX__ || defined __MINGW32__
495 # define WXARC_popen popen
496 # define WXARC_pclose pclose
497 #elif defined _MSC_VER || defined __BORLANDC__
498 # define WXARC_popen _popen
499 # define WXARC_pclose _pclose
501 # define WXARC_NO_POPEN
502 # define WXARC_popen(cmd, type) NULL
503 # define WXARC_pclose(fp)
512 class PFileInputStream
: public wxFFileInputStream
515 PFileInputStream(const wxString
& cmd
) :
516 wxFFileInputStream(WXARC_popen(cmd
.mb_str(), "r" WXARC_b
)) { }
518 { WXARC_pclose(m_file
->fp()); m_file
->Detach(); }
521 class PFileOutputStream
: public wxFFileOutputStream
524 PFileOutputStream(const wxString
& cmd
) :
525 wxFFileOutputStream(WXARC_popen(cmd
.mb_str(), "w" WXARC_b
)) { }
527 { WXARC_pclose(m_file
->fp()); m_file
->Detach(); }
531 ///////////////////////////////////////////////////////////////////////////////
534 template <class Classes
>
535 class ArchiveTestCase
: public CppUnit::TestCase
538 ArchiveTestCase(string name
,
540 wxArchiveClassFactory
*factory
,
542 const wxString
& archiver
= wxEmptyString
,
543 const wxString
& unarchiver
= wxEmptyString
);
548 // the classes to test
549 typedef typename
Classes::EntryT EntryT
;
550 typedef typename
Classes::InputStreamT InputStreamT
;
551 typedef typename
Classes::OutputStreamT OutputStreamT
;
552 typedef typename
Classes::ClassFactoryT ClassFactoryT
;
553 typedef typename
Classes::NotifierT NotifierT
;
554 typedef typename
Classes::IterT IterT
;
555 typedef typename
Classes::PairIterT PairIterT
;
557 // the entry point for the test
560 // create the test data
561 void CreateTestData();
562 TestEntry
& Add(const char *name
, const char *data
, int len
= -1);
563 TestEntry
& Add(const char *name
, int len
= 0, int value
= EOF
);
565 // 'archive up' the test data
566 void CreateArchive(wxOutputStream
& out
);
567 void CreateArchive(wxOutputStream
& out
, const wxString
& archiver
);
569 // perform various modifications on the archive
570 void ModifyArchive(wxInputStream
& in
, wxOutputStream
& out
);
572 // extract the archive and verify its contents
573 void ExtractArchive(wxInputStream
& in
);
574 void ExtractArchive(wxInputStream
& in
, const wxString
& unarchiver
);
575 void VerifyDir(wxString
& path
, size_t rootlen
= 0);
577 // tests for the iterators
578 void TestIterator(wxInputStream
& in
);
579 void TestPairIterator(wxInputStream
& in
);
580 void TestSmartIterator(wxInputStream
& in
);
581 void TestSmartPairIterator(wxInputStream
& in
);
583 // try reading two entries at the same time
584 void ReadSimultaneous(TestInputStream
& in
);
587 virtual void OnCreateArchive(OutputStreamT
& WXUNUSED(arc
)) { }
588 virtual void OnSetNotifier(EntryT
& entry
);
590 virtual void OnArchiveExtracted(InputStreamT
& WXUNUSED(arc
),
591 int WXUNUSED(expectedTotal
)) { }
593 virtual void OnCreateEntry( OutputStreamT
& WXUNUSED(arc
),
594 TestEntry
& WXUNUSED(testEntry
),
595 EntryT
*entry
= NULL
) { (void)entry
; }
597 virtual void OnEntryExtracted( EntryT
& WXUNUSED(entry
),
598 const TestEntry
& WXUNUSED(testEntry
),
599 InputStreamT
*arc
= NULL
) { (void)arc
; }
601 typedef std::map
<wxString
, TestEntry
*> TestEntries
;
602 TestEntries m_testEntries
; // test data
603 auto_ptr
<ClassFactoryT
> m_factory
; // factory to make classes
604 int m_options
; // test options
605 wxDateTime m_timeStamp
; // timestamp to give test entries
606 int m_id
; // select between the possibilites
607 wxString m_archiver
; // external archiver
608 wxString m_unarchiver
; // external unarchiver
612 // The only way I could get this to compile on VC++ 5.0 was to pass 'factory'
613 // as a wxArchiveFactory* then cast it, even then only with some ifdefing.
615 template <class Classes
>
616 ArchiveTestCase
<Classes
>::ArchiveTestCase(
619 wxArchiveClassFactory
*factory
,
621 const wxString
& archiver
,
622 const wxString
& unarchiver
)
624 CppUnit::TestCase(name
),
625 #if defined _MSC_VER && _MSC_VER < 1300
626 m_factory(dynamic_cast<Classes::ClassFactoryT
*>(factory
)),
628 m_factory(dynamic_cast<typename
Classes::ClassFactoryT
*>(factory
)),
631 m_timeStamp(1, wxDateTime::Mar
, 2005, 12, 0),
633 m_archiver(archiver
),
634 m_unarchiver(unarchiver
)
636 wxASSERT(m_factory
.get() != NULL
);
639 template <class Classes
>
640 ArchiveTestCase
<Classes
>::~ArchiveTestCase()
642 TestEntries::iterator it
;
643 for (it
= m_testEntries
.begin(); it
!= m_testEntries
.end(); ++it
)
647 template <class Classes
>
648 void ArchiveTestCase
<Classes
>::runTest()
650 TestOutputStream
out(m_options
);
654 if (m_archiver
.empty())
657 CreateArchive(out
, m_archiver
);
659 // check archive could be created
660 CPPUNIT_ASSERT(out
.GetLength() > 0);
662 TestInputStream
in(out
);
666 TestPairIterator(in
);
668 TestSmartIterator(in
);
670 TestSmartPairIterator(in
);
673 if ((m_options
& PipeIn
) == 0) {
674 ReadSimultaneous(in
);
678 ModifyArchive(in
, out
);
681 if (m_unarchiver
.empty())
684 ExtractArchive(in
, m_unarchiver
);
686 // check that all the test entries were found in the archive
687 CPPUNIT_ASSERT(m_testEntries
.empty());
690 template <class Classes
>
691 void ArchiveTestCase
<Classes
>::CreateTestData()
694 Add("text/empty", "");
695 Add("text/small", "Small text file for testing\n"
696 "archive streams in wxWidgets\n");
699 Add("bin/bin1000", 1000);
700 Add("bin/bin4095", 4095);
701 Add("bin/bin4096", 4096);
702 Add("bin/bin4097", 4097);
703 Add("bin/bin16384", 16384);
706 Add("zero/zero5", 5, 0);
707 Add("zero/zero1024", 1024, 109);
708 Add("zero/zero32768", 32768, 106);
709 Add("zero/zero16385", 16385, 119);
714 template <class Classes
>
715 TestEntry
& ArchiveTestCase
<Classes
>::Add(const char *name
,
721 TestEntry
*& entry
= m_testEntries
[wxString(name
, *wxConvCurrent
)];
722 wxASSERT(entry
== NULL
);
723 entry
= new TestEntry(m_timeStamp
, len
, data
);
724 m_timeStamp
+= wxTimeSpan(0, 1, 30);
728 template <class Classes
>
729 TestEntry
& ArchiveTestCase
<Classes
>::Add(const char *name
,
733 wxCharBuffer
buf(len
);
734 for (int i
= 0; i
< len
; i
++)
735 buf
.data()[i
] = (char)(value
== EOF
? rand() : value
);
736 return Add(name
, buf
, len
);
739 // Create an archive using the wx archive classes, write it to 'out'
741 template <class Classes
>
742 void ArchiveTestCase
<Classes
>::CreateArchive(wxOutputStream
& out
)
744 auto_ptr
<OutputStreamT
> arc(m_factory
->NewStream(out
));
745 TestEntries::iterator it
;
747 OnCreateArchive(*arc
);
749 // We want to try creating entries in various different ways, 'choices'
750 // is just a number used to select between all the various possibilities.
753 for (it
= m_testEntries
.begin(); it
!= m_testEntries
.end(); ++it
) {
755 TestEntry
& testEntry
= *it
->second
;
756 wxString name
= it
->first
;
758 // It should be possible to create a directory entry just by supplying
759 // a name that looks like a directory, or alternatively any old name
760 // can be identified as a directory using SetIsDir or PutNextDirEntry
761 bool setIsDir
= name
.Last() == _T('/') && (choices
& 1);
763 name
.erase(name
.length() - 1);
765 // provide some context for the error message so that we know which
766 // iteration of the loop we were on
767 string
error_entry((_T(" '") + name
+ _T("'")).mb_str());
768 string
error_context(" failed for entry" + error_entry
);
770 if ((choices
& 2) || testEntry
.IsText()) {
771 // try PutNextEntry(EntryT *pEntry)
772 auto_ptr
<EntryT
> entry(m_factory
->NewEntry());
773 entry
->SetName(name
, wxPATH_UNIX
);
776 entry
->SetDateTime(testEntry
.GetDateTime());
777 entry
->SetSize(testEntry
.GetLength());
778 OnCreateEntry(*arc
, testEntry
, entry
.get());
779 CPPUNIT_ASSERT_MESSAGE("PutNextEntry" + error_context
,
780 arc
->PutNextEntry(entry
.release()));
783 // try the convenience methods
784 OnCreateEntry(*arc
, testEntry
);
786 CPPUNIT_ASSERT_MESSAGE("PutNextDirEntry" + error_context
,
787 arc
->PutNextDirEntry(name
, testEntry
.GetDateTime()));
789 CPPUNIT_ASSERT_MESSAGE("PutNextEntry" + error_context
,
790 arc
->PutNextEntry(name
, testEntry
.GetDateTime(),
791 testEntry
.GetLength()));
794 if (name
.Last() != _T('/')) {
795 // for non-dirs write the data
796 arc
->Write(testEntry
.GetData(), testEntry
.GetSize());
797 CPPUNIT_ASSERT_MESSAGE("LastWrite check" + error_context
,
798 arc
->LastWrite() == testEntry
.GetSize());
799 // should work with or without explicit CloseEntry
801 CPPUNIT_ASSERT_MESSAGE("CloseEntry" + error_context
,
805 CPPUNIT_ASSERT_MESSAGE("IsOk" + error_context
, arc
->IsOk());
808 // should work with or without explicit Close
810 CPPUNIT_ASSERT(arc
->Close());
813 // Create an archive using an external archive program
815 template <class Classes
>
816 void ArchiveTestCase
<Classes
>::CreateArchive(wxOutputStream
& out
,
817 const wxString
& archiver
)
819 // for an external archiver the test data need to be written to
824 TestEntries::iterator i
;
825 for (i
= m_testEntries
.begin(); i
!= m_testEntries
.end(); ++i
) {
826 wxFileName
fn(i
->first
, wxPATH_UNIX
);
827 TestEntry
& entry
= *i
->second
;
830 fn
.Mkdir(0777, wxPATH_MKDIR_FULL
);
832 wxFileName::Mkdir(fn
.GetPath(), 0777, wxPATH_MKDIR_FULL
);
833 wxFFileOutputStream
fileout(fn
.GetFullPath());
834 fileout
.Write(entry
.GetData(), entry
.GetSize());
838 for (i
= m_testEntries
.begin(); i
!= m_testEntries
.end(); ++i
) {
839 wxFileName
fn(i
->first
, wxPATH_UNIX
);
840 TestEntry
& entry
= *i
->second
;
841 wxDateTime dt
= entry
.GetDateTime();
844 entry
.SetDateTime(wxDateTime());
847 fn
.SetTimes(NULL
, &dt
, NULL
);
850 if ((m_options
& PipeOut
) == 0) {
851 wxFileName
fn(tmpdir
.GetName());
852 fn
.SetExt(_T("arc"));
853 wxString tmparc
= fn
.GetFullPath();
855 // call the archiver to create an archive file
856 system(wxString::Format(archiver
, tmparc
.c_str()).mb_str());
858 // then load the archive file
860 wxFFileInputStream
in(tmparc
);
865 wxRemoveFile(tmparc
);
868 // for the non-seekable test, have the archiver output to "-"
869 // and read the archive via a pipe
870 PFileInputStream
in(wxString::Format(archiver
, _T("-")));
876 // Do a standard set of modification on an archive, delete an entry,
877 // rename an entry and add an entry
879 template <class Classes
>
880 void ArchiveTestCase
<Classes
>::ModifyArchive(wxInputStream
& in
,
883 auto_ptr
<InputStreamT
> arcIn(m_factory
->NewStream(in
));
884 auto_ptr
<OutputStreamT
> arcOut(m_factory
->NewStream(out
));
887 const wxString deleteName
= _T("bin/bin1000");
888 const wxString renameFrom
= _T("zero/zero1024");
889 const wxString renameTo
= _T("zero/newname");
890 const wxString newName
= _T("newfile");
891 const char *newData
= "New file added as a test\n";
893 arcOut
->CopyArchiveMetaData(*arcIn
);
895 while ((pEntry
= arcIn
->GetNextEntry()) != NULL
) {
896 auto_ptr
<EntryT
> entry(pEntry
);
897 OnSetNotifier(*entry
);
898 wxString name
= entry
->GetName(wxPATH_UNIX
);
900 // provide some context for the error message so that we know which
901 // iteration of the loop we were on
902 string
error_entry((_T(" '") + name
+ _T("'")).mb_str());
903 string
error_context(" failed for entry" + error_entry
);
905 if (name
== deleteName
) {
906 TestEntries::iterator it
= m_testEntries
.find(name
);
907 CPPUNIT_ASSERT_MESSAGE(
908 "deletion failed (already deleted?) for" + error_entry
,
909 it
!= m_testEntries
.end());
910 TestEntry
*p
= it
->second
;
911 m_testEntries
.erase(it
);
915 if (name
== renameFrom
) {
916 entry
->SetName(renameTo
);
917 TestEntries::iterator it
= m_testEntries
.find(renameFrom
);
918 CPPUNIT_ASSERT_MESSAGE(
919 "rename failed (already renamed?) for" + error_entry
,
920 it
!= m_testEntries
.end());
921 TestEntry
*p
= it
->second
;
922 m_testEntries
.erase(it
);
923 m_testEntries
[renameTo
] = p
;
926 CPPUNIT_ASSERT_MESSAGE("CopyEntry" + error_context
,
927 arcOut
->CopyEntry(entry
.release(), *arcIn
));
931 // check that the deletion and rename were done
932 CPPUNIT_ASSERT(m_testEntries
.count(deleteName
) == 0);
933 CPPUNIT_ASSERT(m_testEntries
.count(renameFrom
) == 0);
934 CPPUNIT_ASSERT(m_testEntries
.count(renameTo
) == 1);
936 // check that the end of the input archive was reached without error
937 CPPUNIT_ASSERT(arcIn
->Eof());
939 // try adding a new entry
940 TestEntry
& testEntry
= Add(newName
.mb_str(), newData
);
941 auto_ptr
<EntryT
> newentry(m_factory
->NewEntry());
942 newentry
->SetName(newName
);
943 newentry
->SetDateTime(testEntry
.GetDateTime());
944 newentry
->SetSize(testEntry
.GetLength());
945 OnCreateEntry(*arcOut
, testEntry
, newentry
.get());
946 OnSetNotifier(*newentry
);
947 CPPUNIT_ASSERT(arcOut
->PutNextEntry(newentry
.release()));
948 CPPUNIT_ASSERT(arcOut
->Write(newData
, strlen(newData
)).IsOk());
950 // should work with or without explicit Close
952 CPPUNIT_ASSERT(arcOut
->Close());
955 // Extract an archive using the wx archive classes
957 template <class Classes
>
958 void ArchiveTestCase
<Classes
>::ExtractArchive(wxInputStream
& in
)
960 typedef Ptr
<EntryT
> EntryPtr
;
961 typedef std::list
<EntryPtr
> Entries
;
962 typedef typename
Entries::iterator EntryIter
;
964 auto_ptr
<InputStreamT
> arc(m_factory
->NewStream(in
));
965 int expectedTotal
= m_testEntries
.size();
969 if ((m_options
& PipeIn
) == 0)
970 OnArchiveExtracted(*arc
, expectedTotal
);
972 while (entry
= EntryPtr(arc
->GetNextEntry()), entry
.get() != NULL
) {
973 wxString name
= entry
->GetName(wxPATH_UNIX
);
975 // provide some context for the error message so that we know which
976 // iteration of the loop we were on
977 string
error_entry((_T(" '") + name
+ _T("'")).mb_str());
978 string
error_context(" failed for entry" + error_entry
);
980 TestEntries::iterator it
= m_testEntries
.find(name
);
981 CPPUNIT_ASSERT_MESSAGE(
982 "archive contains an entry that shouldn't be there" + error_entry
,
983 it
!= m_testEntries
.end());
985 const TestEntry
& testEntry
= *it
->second
;
987 wxDateTime dt
= testEntry
.GetDateTime();
989 CPPUNIT_ASSERT_MESSAGE("timestamp check" + error_context
,
990 dt
== entry
->GetDateTime());
992 // non-seekable entries are allowed to have GetSize == wxInvalidOffset
993 // until the end of the entry's data has been read past
994 CPPUNIT_ASSERT_MESSAGE("entry size check" + error_context
,
995 testEntry
.GetLength() == entry
->GetSize() ||
996 ((m_options
& PipeIn
) != 0 && entry
->GetSize() == wxInvalidOffset
));
997 CPPUNIT_ASSERT_MESSAGE(
998 "arc->GetLength() == entry->GetSize()" + error_context
,
999 arc
->GetLength() == entry
->GetSize());
1001 if (name
.Last() != _T('/'))
1003 CPPUNIT_ASSERT_MESSAGE("!IsDir" + error_context
,
1005 wxCharBuffer
buf(testEntry
.GetSize() + 1);
1006 CPPUNIT_ASSERT_MESSAGE("Read until Eof" + error_context
,
1007 arc
->Read(buf
.data(), testEntry
.GetSize() + 1).Eof());
1008 CPPUNIT_ASSERT_MESSAGE("LastRead check" + error_context
,
1009 arc
->LastRead() == testEntry
.GetSize());
1010 CPPUNIT_ASSERT_MESSAGE("data compare" + error_context
,
1011 !memcmp(buf
.data(), testEntry
.GetData(), testEntry
.GetSize()));
1013 CPPUNIT_ASSERT_MESSAGE("IsDir" + error_context
, entry
->IsDir());
1016 // GetSize() must return the right result in all cases after all the
1017 // data has been read
1018 CPPUNIT_ASSERT_MESSAGE("entry size check" + error_context
,
1019 testEntry
.GetLength() == entry
->GetSize());
1020 CPPUNIT_ASSERT_MESSAGE(
1021 "arc->GetLength() == entry->GetSize()" + error_context
,
1022 arc
->GetLength() == entry
->GetSize());
1024 if ((m_options
& PipeIn
) == 0) {
1025 OnEntryExtracted(*entry
, testEntry
, arc
.get());
1027 m_testEntries
.erase(it
);
1029 entries
.push_back(entry
);
1033 // check that the end of the input archive was reached without error
1034 CPPUNIT_ASSERT(arc
->Eof());
1036 // for non-seekable streams these data are only guaranteed to be
1037 // available once the end of the archive has been reached
1038 if (m_options
& PipeIn
) {
1039 for (EntryIter i
= entries
.begin(); i
!= entries
.end(); ++i
) {
1040 wxString name
= (*i
)->GetName(wxPATH_UNIX
);
1041 TestEntries::iterator j
= m_testEntries
.find(name
);
1042 OnEntryExtracted(**i
, *j
->second
);
1044 m_testEntries
.erase(j
);
1046 OnArchiveExtracted(*arc
, expectedTotal
);
1050 // Extract an archive using an external unarchive program
1052 template <class Classes
>
1053 void ArchiveTestCase
<Classes
>::ExtractArchive(wxInputStream
& in
,
1054 const wxString
& unarchiver
)
1056 // for an external unarchiver, unarchive to a tempdir
1059 if ((m_options
& PipeIn
) == 0) {
1060 wxFileName
fn(tmpdir
.GetName());
1061 fn
.SetExt(_T("arc"));
1062 wxString tmparc
= fn
.GetFullPath();
1064 if (m_options
& Stub
)
1065 in
.SeekI(TestOutputStream::STUB_SIZE
* 2);
1067 // write the archive to a temporary file
1069 wxFFileOutputStream
out(tmparc
);
1075 system(wxString::Format(unarchiver
, tmparc
.c_str()).mb_str());
1076 wxRemoveFile(tmparc
);
1079 // for the non-seekable test, have the archiver extract "-" and
1080 // feed it the archive via a pipe
1081 PFileOutputStream
out(wxString::Format(unarchiver
, _T("-")));
1086 wxString dir
= tmpdir
.GetName();
1090 // Verifies the files produced by an external unarchiver are as expected
1092 template <class Classes
>
1093 void ArchiveTestCase
<Classes
>::VerifyDir(wxString
& path
, size_t rootlen
/*=0*/)
1096 path
+= wxFileName::GetPathSeparator();
1097 int pos
= path
.length();
1103 if (dir
.Open(path
) && dir
.GetFirst(&name
)) {
1105 path
.replace(pos
, wxString::npos
, name
);
1106 name
= m_factory
->GetInternalName(
1107 path
.substr(rootlen
, wxString::npos
));
1109 bool isDir
= wxDirExists(path
);
1113 // provide some context for the error message so that we know which
1114 // iteration of the loop we were on
1115 string
error_entry((_T(" '") + name
+ _T("'")).mb_str());
1116 string
error_context(" failed for entry" + error_entry
);
1118 TestEntries::iterator it
= m_testEntries
.find(name
);
1119 CPPUNIT_ASSERT_MESSAGE(
1120 "archive contains an entry that shouldn't be there"
1122 it
!= m_testEntries
.end());
1124 const TestEntry
& testEntry
= *it
->second
;
1127 CPPUNIT_ASSERT_MESSAGE("timestamp check" + error_context
,
1128 testEntry
.GetDateTime() ==
1129 wxFileName(path
).GetModificationTime());
1132 wxFFileInputStream
in(path
);
1133 CPPUNIT_ASSERT_MESSAGE(
1134 "entry not found in archive" + error_entry
, in
.Ok());
1136 size_t size
= (size_t)in
.GetLength();
1137 wxCharBuffer
buf(size
);
1138 CPPUNIT_ASSERT_MESSAGE("Read" + error_context
,
1139 in
.Read(buf
.data(), size
).LastRead() == size
);
1140 CPPUNIT_ASSERT_MESSAGE("size check" + error_context
,
1141 testEntry
.GetSize() == size
);
1142 CPPUNIT_ASSERT_MESSAGE("data compare" + error_context
,
1143 memcmp(buf
.data(), testEntry
.GetData(), size
) == 0);
1146 VerifyDir(path
, rootlen
);
1150 m_testEntries
.erase(it
);
1152 while (dir
.GetNext(&name
));
1156 // test the simple iterators that give away ownership of an entry
1158 template <class Classes
>
1159 void ArchiveTestCase
<Classes
>::TestIterator(wxInputStream
& in
)
1161 typedef std::list
<EntryT
*> ArchiveCatalog
;
1162 typedef typename
ArchiveCatalog::iterator CatalogIter
;
1164 auto_ptr
<InputStreamT
> arc(m_factory
->NewStream(in
));
1167 #ifdef WXARC_MEMBER_TEMPLATES
1168 ArchiveCatalog
cat((IterT
)*arc
, IterT());
1171 for (IterT
i(*arc
); i
!= IterT(); ++i
)
1175 for (CatalogIter it
= cat
.begin(); it
!= cat
.end(); ++it
) {
1176 auto_ptr
<EntryT
> entry(*it
);
1177 count
+= m_testEntries
.count(entry
->GetName(wxPATH_UNIX
));
1180 CPPUNIT_ASSERT(m_testEntries
.size() == cat
.size());
1181 CPPUNIT_ASSERT(count
== cat
.size());
1184 // test the pair iterators that can be used to load a std::map or wxHashMap
1185 // these also give away ownership of entries
1187 template <class Classes
>
1188 void ArchiveTestCase
<Classes
>::TestPairIterator(wxInputStream
& in
)
1190 typedef std::map
<wxString
, EntryT
*> ArchiveCatalog
;
1191 typedef typename
ArchiveCatalog::iterator CatalogIter
;
1193 auto_ptr
<InputStreamT
> arc(m_factory
->NewStream(in
));
1196 #ifdef WXARC_MEMBER_TEMPLATES
1197 ArchiveCatalog
cat((PairIterT
)*arc
, PairIterT());
1200 for (PairIterT
i(*arc
); i
!= PairIterT(); ++i
)
1204 for (CatalogIter it
= cat
.begin(); it
!= cat
.end(); ++it
) {
1205 auto_ptr
<EntryT
> entry(it
->second
);
1206 count
+= m_testEntries
.count(entry
->GetName(wxPATH_UNIX
));
1209 CPPUNIT_ASSERT(m_testEntries
.size() == cat
.size());
1210 CPPUNIT_ASSERT(count
== cat
.size());
1213 // simple iterators using smart pointers, no need to worry about ownership
1215 template <class Classes
>
1216 void ArchiveTestCase
<Classes
>::TestSmartIterator(wxInputStream
& in
)
1218 typedef std::list
<Ptr
<EntryT
> > ArchiveCatalog
;
1219 typedef typename
ArchiveCatalog::iterator CatalogIter
;
1220 typedef wxArchiveIterator
<InputStreamT
, Ptr
<EntryT
> > Iter
;
1222 auto_ptr
<InputStreamT
> arc(m_factory
->NewStream(in
));
1224 #ifdef WXARC_MEMBER_TEMPLATES
1225 ArchiveCatalog
cat((Iter
)*arc
, Iter());
1228 for (Iter
i(*arc
); i
!= Iter(); ++i
)
1232 CPPUNIT_ASSERT(m_testEntries
.size() == cat
.size());
1234 for (CatalogIter it
= cat
.begin(); it
!= cat
.end(); ++it
)
1235 CPPUNIT_ASSERT(m_testEntries
.count((*it
)->GetName(wxPATH_UNIX
)));
1238 // pair iterator using smart pointers
1240 template <class Classes
>
1241 void ArchiveTestCase
<Classes
>::TestSmartPairIterator(wxInputStream
& in
)
1243 #if defined _MSC_VER && defined _MSC_VER < 1200
1244 // With VC++ 5.0 the '=' operator of std::pair breaks when the second
1245 // type is Ptr<EntryT>, so this iterator can't be made to work.
1248 typedef std::map
<wxString
, Ptr
<EntryT
> > ArchiveCatalog
;
1249 typedef typename
ArchiveCatalog::iterator CatalogIter
;
1250 typedef wxArchiveIterator
<InputStreamT
,
1251 std::pair
<wxString
, Ptr
<EntryT
> > > PairIter
;
1253 auto_ptr
<InputStreamT
> arc(m_factory
->NewStream(in
));
1255 #ifdef WXARC_MEMBER_TEMPLATES
1256 ArchiveCatalog
cat((PairIter
)*arc
, PairIter());
1259 for (PairIter
i(*arc
); i
!= PairIter(); ++i
)
1263 CPPUNIT_ASSERT(m_testEntries
.size() == cat
.size());
1265 for (CatalogIter it
= cat
.begin(); it
!= cat
.end(); ++it
)
1266 CPPUNIT_ASSERT(m_testEntries
.count(it
->second
->GetName(wxPATH_UNIX
)));
1270 // try reading two entries at the same time
1272 template <class Classes
>
1273 void ArchiveTestCase
<Classes
>::ReadSimultaneous(TestInputStream
& in
)
1275 typedef std::map
<wxString
, Ptr
<EntryT
> > ArchiveCatalog
;
1276 typedef wxArchiveIterator
<InputStreamT
,
1277 std::pair
<wxString
, Ptr
<EntryT
> > > PairIter
;
1279 // create two archive input streams
1280 TestInputStream
in2(in
);
1281 auto_ptr
<InputStreamT
> arc(m_factory
->NewStream(in
));
1282 auto_ptr
<InputStreamT
> arc2(m_factory
->NewStream(in2
));
1285 #ifdef WXARC_MEMBER_TEMPLATES
1286 ArchiveCatalog
cat((PairIter
)*arc
, PairIter());
1289 for (PairIter
i(*arc
); i
!= PairIter(); ++i
)
1293 // the names of two entries to read
1294 const wxChar
*name
= _T("text/small");
1295 const wxChar
*name2
= _T("bin/bin1000");
1298 typename
ArchiveCatalog::iterator j
;
1299 CPPUNIT_ASSERT((j
= cat
.find(name
)) != cat
.end());
1300 CPPUNIT_ASSERT(arc
->OpenEntry(*j
->second
));
1301 CPPUNIT_ASSERT((j
= cat
.find(name2
)) != cat
.end());
1302 CPPUNIT_ASSERT(arc2
->OpenEntry(*j
->second
));
1304 // get pointers to the expected data
1305 TestEntries::iterator k
;
1306 CPPUNIT_ASSERT((k
= m_testEntries
.find(name
)) != m_testEntries
.end());
1307 TestEntry
*entry
= k
->second
;
1308 CPPUNIT_ASSERT((k
= m_testEntries
.find(name2
)) != m_testEntries
.end());
1309 TestEntry
*entry2
= k
->second
;
1311 size_t count
= 0, count2
= 0;
1312 size_t size
= entry
->GetSize(), size2
= entry2
->GetSize();
1313 const char *data
= entry
->GetData(), *data2
= entry2
->GetData();
1315 // read and check the two entries in parallel, character by character
1316 while (arc
->IsOk() || arc2
->IsOk()) {
1317 char ch
= arc
->GetC();
1318 if (arc
->LastRead() == 1) {
1319 CPPUNIT_ASSERT(count
< size
);
1320 CPPUNIT_ASSERT(ch
== data
[count
++]);
1322 char ch2
= arc2
->GetC();
1323 if (arc2
->LastRead() == 1) {
1324 CPPUNIT_ASSERT(count2
< size2
);
1325 CPPUNIT_ASSERT(ch2
== data2
[count2
++]);
1329 CPPUNIT_ASSERT(arc
->Eof());
1330 CPPUNIT_ASSERT(arc2
->Eof());
1331 CPPUNIT_ASSERT(count
== size
);
1332 CPPUNIT_ASSERT(count2
== size2
);
1335 // Nothing useful can be done with a generic notifier yet, so just test one
1338 template <class NotifierT
, class EntryT
>
1339 class ArchiveNotifier
: public NotifierT
1342 void OnEntryUpdated(EntryT
& WXUNUSED(entry
)) { }
1345 template <class Classes
>
1346 void ArchiveTestCase
<Classes
>::OnSetNotifier(EntryT
& entry
)
1348 static ArchiveNotifier
<NotifierT
, EntryT
> notifier
;
1349 entry
.SetNotifier(notifier
);
1353 ///////////////////////////////////////////////////////////////////////////////
1354 // ArchiveTestCase<ZipClasses> could be used directly, but instead this
1355 // derived class is used so that zip specific features can be tested.
1357 class ZipTestCase
: public ArchiveTestCase
<ZipClasses
>
1360 ZipTestCase(string name
,
1363 const wxString
& archiver
= wxEmptyString
,
1364 const wxString
& unarchiver
= wxEmptyString
)
1366 ArchiveTestCase
<ZipClasses
>(name
, id
, new wxZipClassFactory
,
1367 options
, archiver
, unarchiver
),
1372 void OnCreateArchive(wxZipOutputStream
& zip
);
1374 void OnArchiveExtracted(wxZipInputStream
& zip
, int expectedTotal
);
1376 void OnCreateEntry(wxZipOutputStream
& zip
,
1377 TestEntry
& testEntry
,
1380 void OnEntryExtracted(wxZipEntry
& entry
,
1381 const TestEntry
& testEntry
,
1382 wxZipInputStream
*arc
);
1384 void OnSetNotifier(EntryT
& entry
);
1390 void ZipTestCase::OnCreateArchive(wxZipOutputStream
& zip
)
1392 m_comment
<< _T("Comment for test ") << m_id
;
1393 zip
.SetComment(m_comment
);
1396 void ZipTestCase::OnArchiveExtracted(wxZipInputStream
& zip
, int expectedTotal
)
1398 CPPUNIT_ASSERT(zip
.GetComment() == m_comment
);
1399 CPPUNIT_ASSERT(zip
.GetTotalEntries() == expectedTotal
);
1402 void ZipTestCase::OnCreateEntry(wxZipOutputStream
& zip
,
1403 TestEntry
& testEntry
,
1406 zip
.SetLevel((m_id
+ m_count
) % 10);
1409 switch ((m_id
+ m_count
) % 5) {
1412 wxString comment
= _T("Comment for ") + entry
->GetName();
1413 entry
->SetComment(comment
);
1414 // lowercase the expected result, and the notifier should do
1415 // the same for the zip entries when ModifyArchive() runs
1416 testEntry
.SetComment(comment
.Lower());
1420 entry
->SetMethod(wxZIP_METHOD_STORE
);
1423 entry
->SetMethod(wxZIP_METHOD_DEFLATE
);
1426 entry
->SetIsText(testEntry
.IsText());
1432 void ZipTestCase::OnEntryExtracted(wxZipEntry
& entry
,
1433 const TestEntry
& testEntry
,
1434 wxZipInputStream
*arc
)
1436 // provide some context for the error message so that we know which
1437 // iteration of the loop we were on
1438 wxString name
= _T(" '") + entry
.GetName() + _T("'");
1439 string
error_entry(name
.mb_str());
1440 string
error_context(" failed for entry" + error_entry
);
1442 CPPUNIT_ASSERT_MESSAGE("GetComment" + error_context
,
1443 entry
.GetComment() == testEntry
.GetComment());
1445 // for seekable streams, GetNextEntry() doesn't read the local header so
1446 // call OpenEntry() to do it
1447 if (arc
&& (m_options
& PipeIn
) == 0 && entry
.IsDir())
1448 arc
->OpenEntry(entry
);
1450 CPPUNIT_ASSERT_MESSAGE("IsText" + error_context
,
1451 entry
.IsText() == testEntry
.IsText());
1453 CPPUNIT_ASSERT_MESSAGE("Extra/LocalExtra mismatch for entry" + error_entry
,
1454 (entry
.GetExtraLen() != 0 && entry
.GetLocalExtraLen() != 0) ||
1455 (entry
.GetExtraLen() == 0 && entry
.GetLocalExtraLen() == 0));
1458 // check the notifier mechanism by using it to fold the entry comments to
1461 class ZipNotifier
: public wxZipNotifier
1464 void OnEntryUpdated(wxZipEntry
& entry
);
1467 void ZipNotifier::OnEntryUpdated(wxZipEntry
& entry
)
1469 entry
.SetComment(entry
.GetComment().Lower());
1472 void ZipTestCase::OnSetNotifier(EntryT
& entry
)
1474 static ZipNotifier notifier
;
1475 entry
.SetNotifier(notifier
);
1479 ///////////////////////////////////////////////////////////////////////////////
1480 // 'zip - -' produces local headers without the size field set. This is a
1481 // case not covered by all the other tests, so this class tests it as a
1484 class ZipPipeTestCase
: public CppUnit::TestCase
1487 ZipPipeTestCase(string name
, int options
) :
1488 CppUnit::TestCase(name
), m_options(options
) { }
1495 void ZipPipeTestCase::runTest()
1497 TestOutputStream
out(m_options
);
1499 wxString testdata
= _T("test data to pipe through zip");
1500 wxString cmd
= _T("echo ") + testdata
+ _T(" | zip -q - -");
1503 PFileInputStream
in(cmd
);
1508 TestInputStream
in(out
);
1509 wxZipInputStream
zip(in
);
1511 auto_ptr
<wxZipEntry
> entry(zip
.GetNextEntry());
1512 CPPUNIT_ASSERT(entry
.get() != NULL
);
1514 if ((m_options
& PipeIn
) == 0)
1515 CPPUNIT_ASSERT(entry
->GetSize() != wxInvalidOffset
);
1518 size_t len
= zip
.Read(buf
, sizeof(buf
) - 1).LastRead();
1520 while (len
> 0 && buf
[len
- 1] <= 32)
1524 CPPUNIT_ASSERT(zip
.Eof());
1525 CPPUNIT_ASSERT(wxString(buf
, *wxConvCurrent
) == testdata
);
1529 ///////////////////////////////////////////////////////////////////////////////
1532 class ArchiveTestSuite
: public CppUnit::TestSuite
1536 static CppUnit::Test
*suite()
1537 { return (new ArchiveTestSuite
)->makeSuite(); }
1543 ArchiveTestSuite
*makeSuite();
1544 void AddCmd(wxArrayString
& cmdlist
, const wxString
& cmd
);
1545 bool IsInPath(const wxString
& cmd
);
1547 string
Description(const wxString
& type
,
1549 bool genericInterface
= false,
1550 const wxString
& archiver
= wxEmptyString
,
1551 const wxString
& unarchiver
= wxEmptyString
);
1554 ArchiveTestSuite::ArchiveTestSuite()
1555 : CppUnit::TestSuite("ArchiveTestSuite"),
1558 m_path
.AddEnvList(_T("PATH"));
1561 // add the command for an external archiver to the list, testing for it in
1564 void ArchiveTestSuite::AddCmd(wxArrayString
& cmdlist
, const wxString
& cmd
)
1566 if (cmdlist
.empty())
1567 cmdlist
.push_back(_T(""));
1569 cmdlist
.push_back(cmd
);
1572 bool ArchiveTestSuite::IsInPath(const wxString
& cmd
)
1574 wxString c
= cmd
.BeforeFirst(_T(' '));
1578 return !m_path
.FindValidPath(c
).empty();
1581 // make the test suite
1583 ArchiveTestSuite
*ArchiveTestSuite::makeSuite()
1585 typedef wxArrayString::iterator Iter
;
1586 wxArrayString zippers
;
1587 wxArrayString unzippers
;
1589 AddCmd(zippers
, _T("zip -qr %s *"));
1590 AddCmd(unzippers
, _T("unzip -q %s"));
1592 for (int genInterface
= 0; genInterface
< 2; genInterface
++)
1593 for (Iter i
= unzippers
.begin(); i
!= unzippers
.end(); ++i
)
1594 for (Iter j
= zippers
.begin(); j
!= zippers
.end(); ++j
)
1595 for (int options
= 0; options
<= AllOptions
; options
++)
1597 // unzip doesn't support piping in the zip
1598 if ((options
& PipeIn
) && !i
->empty())
1600 #ifdef WXARC_NO_POPEN
1601 // if no popen then can use piped output of zip
1602 if ((options
& PipeOut
) && !j
->empty())
1605 string name
= Description(_T("wxZip"), options
,
1606 genInterface
!= 0, *j
, *i
);
1609 addTest(new ArchiveTestCase
<ArchiveClasses
>(
1611 new wxZipClassFactory
,
1614 addTest(new ZipTestCase(name
, m_id
, options
, *j
, *i
));
1619 #ifndef WXARC_NO_POPEN
1620 // if have popen then can check the piped output of 'zip - -'
1621 if (IsInPath(_T("zip")))
1622 for (int options
= 0; options
<= PipeIn
; options
+= PipeIn
) {
1623 string name
= Description(_T("ZipPipeTestCase"), options
);
1624 addTest(new ZipPipeTestCase(name
, options
));
1632 // make a display string for the option bits
1634 string
ArchiveTestSuite::Description(const wxString
& type
,
1636 bool genericInterface
,
1637 const wxString
& archiver
,
1638 const wxString
& unarchiver
)
1641 descr
<< m_id
<< _T(" ");
1643 if (genericInterface
)
1644 descr
<< _T("wxArchive (") << type
<< _T(")");
1648 if (!archiver
.empty())
1649 descr
<< _T(" ") << archiver
.BeforeFirst(_T(' '));
1650 if (!unarchiver
.empty())
1651 descr
<< _T(" ") << unarchiver
.BeforeFirst(_T(' '));
1655 if ((options
& PipeIn
) != 0)
1656 optstr
+= _T("|PipeIn");
1657 if ((options
& PipeOut
) != 0)
1658 optstr
+= _T("|PipeOut");
1659 if ((options
& Stub
) != 0)
1660 optstr
+= _T("|Stub");
1661 if (!optstr
.empty())
1662 optstr
= _T(" (") + optstr
.substr(1) + _T(")");
1666 return (const char*)descr
.mb_str();
1669 // register in the unnamed registry so that these tests are run by default
1670 CPPUNIT_TEST_SUITE_REGISTRATION(ArchiveTestSuite
);
1672 // also include in it's own registry so that these tests can be run alone
1673 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(ArchiveTestSuite
, "ArchiveTestSuite");
1675 #endif // wxUSE_STREAMS