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 // This sample uses some advanced typedef syntax that messes
25 // up MSVC 6 - turn off its warning about it
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 [] (char*) 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 char *d
= new char[len
];
143 memcpy(d
, data
, len
);
146 for (int i
= 0; i
< len
&& m_isText
; i
++)
147 m_isText
= (signed char)m_data
[i
] > 0;
151 ///////////////////////////////////////////////////////////////////////////////
152 // TestOutputStream and TestInputStream are memory streams which can be
153 // seekable or non-seekable.
155 class TestOutputStream
: public wxOutputStream
158 TestOutputStream(int options
);
160 ~TestOutputStream() { delete [] m_data
; }
162 int GetOptions() const { return m_options
; }
163 wxFileOffset
GetLength() const { return m_size
; }
165 // gives away the data, this stream is then empty, and can be reused
166 void GetData(const char*& data
, size_t& size
);
168 enum { STUB_SIZE
= 2048, INITIAL_SIZE
= 0x18000, SEEK_LIMIT
= 0x100000 };
173 wxFileOffset
OnSysSeek(wxFileOffset pos
, wxSeekMode mode
);
174 wxFileOffset
OnSysTell() const;
175 size_t OnSysWrite(const void *buffer
, size_t size
);
184 TestOutputStream::TestOutputStream(int options
)
190 void TestOutputStream::Init()
197 if (m_options
& Stub
) {
198 wxCharBuffer
buf(STUB_SIZE
);
199 memset(buf
.data(), 0, STUB_SIZE
);
200 Write(buf
, STUB_SIZE
);
204 wxFileOffset
TestOutputStream::OnSysSeek(wxFileOffset pos
, wxSeekMode mode
)
206 if ((m_options
& PipeOut
) == 0) {
208 case wxFromStart
: break;
209 case wxFromCurrent
: pos
+= m_pos
; break;
210 case wxFromEnd
: pos
+= m_size
; break;
212 if (pos
< 0 || pos
> SEEK_LIMIT
)
213 return wxInvalidOffset
;
217 return wxInvalidOffset
;
220 wxFileOffset
TestOutputStream::OnSysTell() const
222 return (m_options
& PipeOut
) == 0 ? (wxFileOffset
)m_pos
: wxInvalidOffset
;
225 size_t TestOutputStream::OnSysWrite(const void *buffer
, size_t size
)
227 if (!IsOk() || !size
)
229 m_lasterror
= wxSTREAM_WRITE_ERROR
;
231 size_t newsize
= m_pos
+ size
;
232 wxCHECK(newsize
> m_pos
, 0);
234 if (m_capacity
< newsize
) {
235 size_t capacity
= m_capacity
? m_capacity
: INITIAL_SIZE
;
237 while (capacity
< newsize
) {
239 wxCHECK(capacity
> m_capacity
, 0);
242 char *buf
= new char[capacity
];
244 memcpy(buf
, m_data
, m_capacity
);
247 m_capacity
= capacity
;
250 memcpy(m_data
+ m_pos
, buffer
, size
);
254 m_lasterror
= wxSTREAM_NO_ERROR
;
259 void TestOutputStream::GetData(const char*& data
, size_t& size
)
264 if (m_options
& Stub
) {
268 if (size
> m_capacity
) {
270 memcpy(d
+ STUB_SIZE
, m_data
, m_size
);
274 memmove(d
+ STUB_SIZE
, d
, m_size
);
277 memset(d
, 0, STUB_SIZE
);
285 class TestInputStream
: public wxInputStream
288 // ctor takes the data from the output stream, which is then empty
289 TestInputStream(TestOutputStream
& out
) : m_data(NULL
) { SetData(out
); }
291 TestInputStream(const TestInputStream
& in
);
292 ~TestInputStream() { delete [] (char*) m_data
; }
295 wxFileOffset
GetLength() const { return m_size
; }
296 void SetData(TestOutputStream
& out
);
299 wxFileOffset
OnSysSeek(wxFileOffset pos
, wxSeekMode mode
);
300 wxFileOffset
OnSysTell() const;
301 size_t OnSysRead(void *buffer
, size_t size
);
309 TestInputStream::TestInputStream(const TestInputStream
& in
)
310 : m_options(in
.m_options
),
314 char *p
= new char[m_size
];
315 memcpy(p
, in
.m_data
, m_size
);
319 void TestInputStream::Rewind()
321 if ((m_options
& Stub
) && (m_options
& PipeIn
))
322 m_pos
= TestOutputStream::STUB_SIZE
* 2;
334 void TestInputStream::SetData(TestOutputStream
& out
)
336 delete [] (char*) m_data
;
337 m_options
= out
.GetOptions();
338 out
.GetData(m_data
, m_size
);
343 wxFileOffset
TestInputStream::OnSysSeek(wxFileOffset pos
, wxSeekMode mode
)
345 if ((m_options
& PipeIn
) == 0) {
347 case wxFromStart
: break;
348 case wxFromCurrent
: pos
+= m_pos
; break;
349 case wxFromEnd
: pos
+= m_size
; break;
351 if (pos
< 0 || pos
> TestOutputStream::SEEK_LIMIT
)
352 return wxInvalidOffset
;
356 return wxInvalidOffset
;
359 wxFileOffset
TestInputStream::OnSysTell() const
361 return (m_options
& PipeIn
) == 0 ? (wxFileOffset
)m_pos
: wxInvalidOffset
;
364 size_t TestInputStream::OnSysRead(void *buffer
, size_t size
)
366 if (!IsOk() || !size
)
368 if (m_size
<= m_pos
) {
369 m_lasterror
= wxSTREAM_EOF
;
373 if (m_size
- m_pos
< size
)
374 size
= m_size
- m_pos
;
375 memcpy(buffer
, m_data
+ m_pos
, size
);
381 ///////////////////////////////////////////////////////////////////////////////
382 // minimal non-intrusive reference counting pointer for testing the iterators
384 template <class T
> class Ptr
387 explicit Ptr(T
* p
= NULL
) : m_p(p
), m_count(new int) { *m_count
= 1; }
388 Ptr(const Ptr
& sp
) : m_p(sp
.m_p
), m_count(sp
.m_count
) { ++*m_count
; }
391 Ptr
& operator =(const Ptr
& sp
) {
395 m_count
= sp
.m_count
;
401 T
* get() const { return m_p
; }
402 T
* operator->() const { return m_p
; }
403 T
& operator*() const { return *m_p
; }
407 if (--*m_count
== 0) {
418 ///////////////////////////////////////////////////////////////////////////////
419 // Clean-up for temp directory
426 wxString
GetName() const { return m_tmp
; }
429 void RemoveDir(wxString
& path
);
436 wxString tmp
= wxFileName::CreateTempFileName(_T("arctest-"));
437 if (tmp
!= wxEmptyString
) {
439 m_original
= wxGetCwd();
440 CPPUNIT_ASSERT(wxMkdir(tmp
, 0700));
442 CPPUNIT_ASSERT(wxSetWorkingDirectory(tmp
));
448 if (m_tmp
!= wxEmptyString
) {
449 wxSetWorkingDirectory(m_original
);
454 void TempDir::RemoveDir(wxString
& path
)
456 wxCHECK_RET(!m_tmp
.empty() && path
.substr(0, m_tmp
.length()) == m_tmp
,
457 _T("remove '") + path
+ _T("' fails safety check"));
459 const wxChar
*files
[] = {
469 _T("zero/zero32768"),
470 _T("zero/zero16385"),
475 const wxChar
*dirs
[] = {
476 _T("text/"), _T("bin/"), _T("zero/"), _T("empty/")
479 wxString tmp
= m_tmp
+ wxFileName::GetPathSeparator();
482 for (i
= 0; i
< WXSIZEOF(files
); i
++)
483 wxRemoveFile(tmp
+ wxFileName(files
[i
], wxPATH_UNIX
).GetFullPath());
485 for (i
= 0; i
< WXSIZEOF(dirs
); i
++)
486 wxRmdir(tmp
+ wxFileName(dirs
[i
], wxPATH_UNIX
).GetFullPath());
489 wxLogSysError(_T("can't remove temporary dir '%s'"), m_tmp
.c_str());
493 ///////////////////////////////////////////////////////////////////////////////
494 // wxFFile streams for piping to/from an external program
496 #if defined __UNIX__ || defined __MINGW32__
497 # define WXARC_popen popen
498 # define WXARC_pclose pclose
499 #elif defined _MSC_VER || defined __BORLANDC__
500 # define WXARC_popen _popen
501 # define WXARC_pclose _pclose
503 # define WXARC_NO_POPEN
504 # define WXARC_popen(cmd, type) NULL
505 # define WXARC_pclose(fp)
514 class PFileInputStream
: public wxFFileInputStream
517 PFileInputStream(const wxString
& cmd
) :
518 wxFFileInputStream(WXARC_popen(cmd
.mb_str(), "r" WXARC_b
)) { }
520 { WXARC_pclose(m_file
->fp()); m_file
->Detach(); }
523 class PFileOutputStream
: public wxFFileOutputStream
526 PFileOutputStream(const wxString
& cmd
) :
527 wxFFileOutputStream(WXARC_popen(cmd
.mb_str(), "w" WXARC_b
)) { }
529 { WXARC_pclose(m_file
->fp()); m_file
->Detach(); }
533 ///////////////////////////////////////////////////////////////////////////////
536 template <class Classes
>
537 class ArchiveTestCase
: public CppUnit::TestCase
540 ArchiveTestCase(string name
,
542 wxArchiveClassFactory
*factory
,
544 const wxString
& archiver
= wxEmptyString
,
545 const wxString
& unarchiver
= wxEmptyString
);
550 // the classes to test
551 typedef typename
Classes::EntryT EntryT
;
552 typedef typename
Classes::InputStreamT InputStreamT
;
553 typedef typename
Classes::OutputStreamT OutputStreamT
;
554 typedef typename
Classes::ClassFactoryT ClassFactoryT
;
555 typedef typename
Classes::NotifierT NotifierT
;
556 typedef typename
Classes::IterT IterT
;
557 typedef typename
Classes::PairIterT PairIterT
;
559 // the entry point for the test
562 // create the test data
563 void CreateTestData();
564 TestEntry
& Add(const char *name
, const char *data
, int len
= -1);
565 TestEntry
& Add(const char *name
, int len
= 0, int value
= EOF
);
567 // 'archive up' the test data
568 void CreateArchive(wxOutputStream
& out
);
569 void CreateArchive(wxOutputStream
& out
, const wxString
& archiver
);
571 // perform various modifications on the archive
572 void ModifyArchive(wxInputStream
& in
, wxOutputStream
& out
);
574 // extract the archive and verify its contents
575 void ExtractArchive(wxInputStream
& in
);
576 void ExtractArchive(wxInputStream
& in
, const wxString
& unarchiver
);
577 void VerifyDir(wxString
& path
, size_t rootlen
= 0);
579 // tests for the iterators
580 void TestIterator(wxInputStream
& in
);
581 void TestPairIterator(wxInputStream
& in
);
582 void TestSmartIterator(wxInputStream
& in
);
583 void TestSmartPairIterator(wxInputStream
& in
);
585 // try reading two entries at the same time
586 void ReadSimultaneous(TestInputStream
& in
);
589 virtual void OnCreateArchive(OutputStreamT
& WXUNUSED(arc
)) { }
590 virtual void OnSetNotifier(EntryT
& entry
);
592 virtual void OnArchiveExtracted(InputStreamT
& WXUNUSED(arc
),
593 int WXUNUSED(expectedTotal
)) { }
595 virtual void OnCreateEntry( OutputStreamT
& WXUNUSED(arc
),
596 TestEntry
& WXUNUSED(testEntry
),
597 EntryT
*entry
= NULL
) { (void)entry
; }
599 virtual void OnEntryExtracted( EntryT
& WXUNUSED(entry
),
600 const TestEntry
& WXUNUSED(testEntry
),
601 InputStreamT
*arc
= NULL
) { (void)arc
; }
603 typedef std::map
<wxString
, TestEntry
*> TestEntries
;
604 TestEntries m_testEntries
; // test data
605 auto_ptr
<ClassFactoryT
> m_factory
; // factory to make classes
606 int m_options
; // test options
607 wxDateTime m_timeStamp
; // timestamp to give test entries
608 int m_id
; // select between the possibilites
609 wxString m_archiver
; // external archiver
610 wxString m_unarchiver
; // external unarchiver
614 // The only way I could get this to compile on VC++ 5.0 was to pass 'factory'
615 // as a wxArchiveFactory* then cast it, even then only with some ifdefing.
617 template <class Classes
>
618 ArchiveTestCase
<Classes
>::ArchiveTestCase(
621 wxArchiveClassFactory
*factory
,
623 const wxString
& archiver
,
624 const wxString
& unarchiver
)
626 CppUnit::TestCase(name
),
627 #if defined _MSC_VER && _MSC_VER < 1300
628 m_factory(dynamic_cast<Classes::ClassFactoryT
*>(factory
)),
630 m_factory(dynamic_cast<typename
Classes::ClassFactoryT
*>(factory
)),
633 m_timeStamp(1, wxDateTime::Mar
, 2005, 12, 0),
635 m_archiver(archiver
),
636 m_unarchiver(unarchiver
)
638 wxASSERT(m_factory
.get() != NULL
);
641 template <class Classes
>
642 ArchiveTestCase
<Classes
>::~ArchiveTestCase()
644 TestEntries::iterator it
;
645 for (it
= m_testEntries
.begin(); it
!= m_testEntries
.end(); ++it
)
649 template <class Classes
>
650 void ArchiveTestCase
<Classes
>::runTest()
652 TestOutputStream
out(m_options
);
656 if (m_archiver
.empty())
659 CreateArchive(out
, m_archiver
);
661 // check archive could be created
662 CPPUNIT_ASSERT(out
.GetLength() > 0);
664 TestInputStream
in(out
);
668 TestPairIterator(in
);
670 TestSmartIterator(in
);
672 TestSmartPairIterator(in
);
675 if ((m_options
& PipeIn
) == 0) {
676 ReadSimultaneous(in
);
680 ModifyArchive(in
, out
);
683 if (m_unarchiver
.empty())
686 ExtractArchive(in
, m_unarchiver
);
688 // check that all the test entries were found in the archive
689 CPPUNIT_ASSERT(m_testEntries
.empty());
692 template <class Classes
>
693 void ArchiveTestCase
<Classes
>::CreateTestData()
696 Add("text/empty", "");
697 Add("text/small", "Small text file for testing\n"
698 "archive streams in wxWidgets\n");
701 Add("bin/bin1000", 1000);
702 Add("bin/bin4095", 4095);
703 Add("bin/bin4096", 4096);
704 Add("bin/bin4097", 4097);
705 Add("bin/bin16384", 16384);
708 Add("zero/zero5", 5, 0);
709 Add("zero/zero1024", 1024, 109);
710 Add("zero/zero32768", 32768, 106);
711 Add("zero/zero16385", 16385, 119);
716 template <class Classes
>
717 TestEntry
& ArchiveTestCase
<Classes
>::Add(const char *name
,
723 TestEntry
*& entry
= m_testEntries
[wxString(name
, *wxConvCurrent
)];
724 wxASSERT(entry
== NULL
);
725 entry
= new TestEntry(m_timeStamp
, len
, data
);
726 m_timeStamp
+= wxTimeSpan(0, 1, 30);
730 template <class Classes
>
731 TestEntry
& ArchiveTestCase
<Classes
>::Add(const char *name
,
735 wxCharBuffer
buf(len
);
736 for (int i
= 0; i
< len
; i
++)
737 buf
.data()[i
] = value
== EOF
? rand() : value
;
738 return Add(name
, buf
, len
);
741 // Create an archive using the wx archive classes, write it to 'out'
743 template <class Classes
>
744 void ArchiveTestCase
<Classes
>::CreateArchive(wxOutputStream
& out
)
746 auto_ptr
<OutputStreamT
> arc(m_factory
->NewStream(out
));
747 TestEntries::iterator it
;
749 OnCreateArchive(*arc
);
751 // We want to try creating entries in various different ways, 'choices'
752 // is just a number used to select between all the various possibilities.
755 for (it
= m_testEntries
.begin(); it
!= m_testEntries
.end(); ++it
) {
757 TestEntry
& testEntry
= *it
->second
;
758 wxString name
= it
->first
;
760 // It should be possible to create a directory entry just by supplying
761 // a name that looks like a directory, or alternatively any old name
762 // can be identified as a directory using SetIsDir or PutNextDirEntry
763 bool setIsDir
= name
.Last() == _T('/') && (choices
& 1);
765 name
.erase(name
.length() - 1);
767 // provide some context for the error message so that we know which
768 // iteration of the loop we were on
769 string
error_entry((_T(" '") + name
+ _T("'")).mb_str());
770 string
error_context(" failed for entry" + error_entry
);
772 if ((choices
& 2) || testEntry
.IsText()) {
773 // try PutNextEntry(EntryT *pEntry)
774 auto_ptr
<EntryT
> entry(m_factory
->NewEntry());
775 entry
->SetName(name
, wxPATH_UNIX
);
778 entry
->SetDateTime(testEntry
.GetDateTime());
779 entry
->SetSize(testEntry
.GetLength());
780 OnCreateEntry(*arc
, testEntry
, entry
.get());
781 CPPUNIT_ASSERT_MESSAGE("PutNextEntry" + error_context
,
782 arc
->PutNextEntry(entry
.release()));
785 // try the convenience methods
786 OnCreateEntry(*arc
, testEntry
);
788 CPPUNIT_ASSERT_MESSAGE("PutNextDirEntry" + error_context
,
789 arc
->PutNextDirEntry(name
, testEntry
.GetDateTime()));
791 CPPUNIT_ASSERT_MESSAGE("PutNextEntry" + error_context
,
792 arc
->PutNextEntry(name
, testEntry
.GetDateTime(),
793 testEntry
.GetLength()));
796 if (name
.Last() != _T('/')) {
797 // for non-dirs write the data
798 arc
->Write(testEntry
.GetData(), testEntry
.GetSize());
799 CPPUNIT_ASSERT_MESSAGE("LastWrite check" + error_context
,
800 arc
->LastWrite() == testEntry
.GetSize());
801 // should work with or without explicit CloseEntry
803 CPPUNIT_ASSERT_MESSAGE("CloseEntry" + error_context
,
807 CPPUNIT_ASSERT_MESSAGE("IsOk" + error_context
, arc
->IsOk());
810 // should work with or without explicit Close
812 CPPUNIT_ASSERT(arc
->Close());
815 // Create an archive using an external archive program
817 template <class Classes
>
818 void ArchiveTestCase
<Classes
>::CreateArchive(wxOutputStream
& out
,
819 const wxString
& archiver
)
821 // for an external archiver the test data need to be written to
826 TestEntries::iterator i
;
827 for (i
= m_testEntries
.begin(); i
!= m_testEntries
.end(); ++i
) {
828 wxFileName
fn(i
->first
, wxPATH_UNIX
);
829 TestEntry
& entry
= *i
->second
;
832 fn
.Mkdir(0777, wxPATH_MKDIR_FULL
);
834 wxFileName::Mkdir(fn
.GetPath(), 0777, wxPATH_MKDIR_FULL
);
835 wxFFileOutputStream
fileout(fn
.GetFullPath());
836 fileout
.Write(entry
.GetData(), entry
.GetSize());
840 for (i
= m_testEntries
.begin(); i
!= m_testEntries
.end(); ++i
) {
841 wxFileName
fn(i
->first
, wxPATH_UNIX
);
842 TestEntry
& entry
= *i
->second
;
843 wxDateTime dt
= entry
.GetDateTime();
846 entry
.SetDateTime(wxDateTime());
849 fn
.SetTimes(NULL
, &dt
, NULL
);
852 if ((m_options
& PipeOut
) == 0) {
853 wxFileName
fn(tmpdir
.GetName());
854 fn
.SetExt(_T("arc"));
855 wxString tmparc
= fn
.GetFullPath();
857 // call the archiver to create an archive file
858 system(wxString::Format(archiver
, tmparc
.c_str()).mb_str());
860 // then load the archive file
862 wxFFileInputStream
in(tmparc
);
867 wxRemoveFile(tmparc
);
870 // for the non-seekable test, have the archiver output to "-"
871 // and read the archive via a pipe
872 PFileInputStream
in(wxString::Format(archiver
, _T("-")));
878 // Do a standard set of modification on an archive, delete an entry,
879 // rename an entry and add an entry
881 template <class Classes
>
882 void ArchiveTestCase
<Classes
>::ModifyArchive(wxInputStream
& in
,
885 auto_ptr
<InputStreamT
> arcIn(m_factory
->NewStream(in
));
886 auto_ptr
<OutputStreamT
> arcOut(m_factory
->NewStream(out
));
889 const wxString deleteName
= _T("bin/bin1000");
890 const wxString renameFrom
= _T("zero/zero1024");
891 const wxString renameTo
= _T("zero/newname");
892 const wxString newName
= _T("newfile");
893 const char *newData
= "New file added as a test\n";
895 arcOut
->CopyArchiveMetaData(*arcIn
);
897 auto_ptr
<EntryT
>* pEntry
;
899 for (pEntry
= new auto_ptr
<EntryT
>(arcIn
->GetNextEntry()) ;
900 pEntry
->get() != NULL
;
901 delete pEntry
, pEntry
= new auto_ptr
<EntryT
>(arcIn
->GetNextEntry()))
903 OnSetNotifier(**pEntry
);
904 wxString name
= (*pEntry
)->GetName(wxPATH_UNIX
);
906 // provide some context for the error message so that we know which
907 // iteration of the loop we were on
908 string
error_entry((_T(" '") + name
+ _T("'")).mb_str());
909 string
error_context(" failed for entry" + error_entry
);
911 if (name
== deleteName
) {
912 TestEntries::iterator it
= m_testEntries
.find(name
);
913 CPPUNIT_ASSERT_MESSAGE(
914 "deletion failed (already deleted?) for" + error_entry
,
915 it
!= m_testEntries
.end());
916 TestEntry
*p
= it
->second
;
917 m_testEntries
.erase(it
);
921 if (name
== renameFrom
) {
922 (*pEntry
)->SetName(renameTo
);
923 TestEntries::iterator it
= m_testEntries
.find(renameFrom
);
924 CPPUNIT_ASSERT_MESSAGE(
925 "rename failed (already renamed?) for" + error_entry
,
926 it
!= m_testEntries
.end());
927 TestEntry
*p
= it
->second
;
928 m_testEntries
.erase(it
);
929 m_testEntries
[renameTo
] = p
;
932 CPPUNIT_ASSERT_MESSAGE("CopyEntry" + error_context
,
933 arcOut
->CopyEntry(pEntry
->release(), *arcIn
));
939 // check that the deletion and rename were done
940 CPPUNIT_ASSERT(m_testEntries
.count(deleteName
) == 0);
941 CPPUNIT_ASSERT(m_testEntries
.count(renameFrom
) == 0);
942 CPPUNIT_ASSERT(m_testEntries
.count(renameTo
) == 1);
944 // check that the end of the input archive was reached without error
945 CPPUNIT_ASSERT(arcIn
->Eof());
947 // try adding a new entry
948 TestEntry
& testEntry
= Add(newName
.mb_str(), newData
);
949 auto_ptr
<EntryT
> newentry(m_factory
->NewEntry());
950 newentry
->SetName(newName
);
951 newentry
->SetDateTime(testEntry
.GetDateTime());
952 newentry
->SetSize(testEntry
.GetLength());
953 OnCreateEntry(*arcOut
, testEntry
, newentry
.get());
954 OnSetNotifier(*newentry
);
955 CPPUNIT_ASSERT(arcOut
->PutNextEntry(newentry
.release()));
956 CPPUNIT_ASSERT(arcOut
->Write(newData
, strlen(newData
)).IsOk());
958 // should work with or without explicit Close
960 CPPUNIT_ASSERT(arcOut
->Close());
963 // Extract an archive using the wx archive classes
965 template <class Classes
>
966 void ArchiveTestCase
<Classes
>::ExtractArchive(wxInputStream
& in
)
968 typedef Ptr
<EntryT
> EntryPtr
;
969 typedef std::list
<EntryPtr
> Entries
;
970 typedef typename
Entries::iterator EntryIter
;
972 auto_ptr
<InputStreamT
> arc(m_factory
->NewStream(in
));
973 int expectedTotal
= m_testEntries
.size();
977 if ((m_options
& PipeIn
) == 0)
978 OnArchiveExtracted(*arc
, expectedTotal
);
980 while (entry
= EntryPtr(arc
->GetNextEntry()), entry
.get() != NULL
) {
981 wxString name
= entry
->GetName(wxPATH_UNIX
);
983 // provide some context for the error message so that we know which
984 // iteration of the loop we were on
985 string
error_entry((_T(" '") + name
+ _T("'")).mb_str());
986 string
error_context(" failed for entry" + error_entry
);
988 TestEntries::iterator it
= m_testEntries
.find(name
);
989 CPPUNIT_ASSERT_MESSAGE(
990 "archive contains an entry that shouldn't be there" + error_entry
,
991 it
!= m_testEntries
.end());
993 const TestEntry
& testEntry
= *it
->second
;
995 wxDateTime dt
= testEntry
.GetDateTime();
997 CPPUNIT_ASSERT_MESSAGE("timestamp check" + error_context
,
998 dt
== entry
->GetDateTime());
1000 // non-seekable entries are allowed to have GetSize == wxInvalidOffset
1001 // until the end of the entry's data has been read past
1002 CPPUNIT_ASSERT_MESSAGE("entry size check" + error_context
,
1003 testEntry
.GetLength() == entry
->GetSize() ||
1004 ((m_options
& PipeIn
) != 0 && entry
->GetSize() == wxInvalidOffset
));
1005 CPPUNIT_ASSERT_MESSAGE(
1006 "arc->GetLength() == entry->GetSize()" + error_context
,
1007 arc
->GetLength() == entry
->GetSize());
1009 if (name
.Last() != _T('/'))
1011 CPPUNIT_ASSERT_MESSAGE("!IsDir" + error_context
,
1013 wxCharBuffer
buf(testEntry
.GetSize() + 1);
1014 CPPUNIT_ASSERT_MESSAGE("Read until Eof" + error_context
,
1015 arc
->Read(buf
.data(), testEntry
.GetSize() + 1).Eof());
1016 CPPUNIT_ASSERT_MESSAGE("LastRead check" + error_context
,
1017 arc
->LastRead() == testEntry
.GetSize());
1018 CPPUNIT_ASSERT_MESSAGE("data compare" + error_context
,
1019 !memcmp(buf
.data(), testEntry
.GetData(), testEntry
.GetSize()));
1021 CPPUNIT_ASSERT_MESSAGE("IsDir" + error_context
, entry
->IsDir());
1024 // GetSize() must return the right result in all cases after all the
1025 // data has been read
1026 CPPUNIT_ASSERT_MESSAGE("entry size check" + error_context
,
1027 testEntry
.GetLength() == entry
->GetSize());
1028 CPPUNIT_ASSERT_MESSAGE(
1029 "arc->GetLength() == entry->GetSize()" + error_context
,
1030 arc
->GetLength() == entry
->GetSize());
1032 if ((m_options
& PipeIn
) == 0) {
1033 OnEntryExtracted(*entry
, testEntry
, arc
.get());
1035 m_testEntries
.erase(it
);
1037 entries
.push_back(entry
);
1041 // check that the end of the input archive was reached without error
1042 CPPUNIT_ASSERT(arc
->Eof());
1044 // for non-seekable streams these data are only guaranteed to be
1045 // available once the end of the archive has been reached
1046 if (m_options
& PipeIn
) {
1047 for (EntryIter i
= entries
.begin(); i
!= entries
.end(); ++i
) {
1048 wxString name
= (*i
)->GetName(wxPATH_UNIX
);
1049 TestEntries::iterator j
= m_testEntries
.find(name
);
1050 OnEntryExtracted(**i
, *j
->second
);
1052 m_testEntries
.erase(j
);
1054 OnArchiveExtracted(*arc
, expectedTotal
);
1058 // Extract an archive using an external unarchive program
1060 template <class Classes
>
1061 void ArchiveTestCase
<Classes
>::ExtractArchive(wxInputStream
& in
,
1062 const wxString
& unarchiver
)
1064 // for an external unarchiver, unarchive to a tempdir
1067 if ((m_options
& PipeIn
) == 0) {
1068 wxFileName
fn(tmpdir
.GetName());
1069 fn
.SetExt(_T("arc"));
1070 wxString tmparc
= fn
.GetFullPath();
1072 if (m_options
& Stub
)
1073 in
.SeekI(TestOutputStream::STUB_SIZE
* 2);
1075 // write the archive to a temporary file
1077 wxFFileOutputStream
out(tmparc
);
1083 system(wxString::Format(unarchiver
, tmparc
.c_str()).mb_str());
1084 wxRemoveFile(tmparc
);
1087 // for the non-seekable test, have the archiver extract "-" and
1088 // feed it the archive via a pipe
1089 PFileOutputStream
out(wxString::Format(unarchiver
, _T("-")));
1094 wxString dir
= tmpdir
.GetName();
1098 // Verifies the files produced by an external unarchiver are as expected
1100 template <class Classes
>
1101 void ArchiveTestCase
<Classes
>::VerifyDir(wxString
& path
, size_t rootlen
/*=0*/)
1104 path
+= wxFileName::GetPathSeparator();
1105 int pos
= path
.length();
1111 if (dir
.Open(path
) && dir
.GetFirst(&name
)) {
1113 path
.replace(pos
, wxString::npos
, name
);
1114 name
= m_factory
->GetInternalName(
1115 path
.substr(rootlen
, wxString::npos
));
1117 bool isDir
= wxDirExists(path
);
1121 // provide some context for the error message so that we know which
1122 // iteration of the loop we were on
1123 string
error_entry((_T(" '") + name
+ _T("'")).mb_str());
1124 string
error_context(" failed for entry" + error_entry
);
1126 TestEntries::iterator it
= m_testEntries
.find(name
);
1127 CPPUNIT_ASSERT_MESSAGE(
1128 "archive contains an entry that shouldn't be there"
1130 it
!= m_testEntries
.end());
1132 const TestEntry
& testEntry
= *it
->second
;
1135 CPPUNIT_ASSERT_MESSAGE("timestamp check" + error_context
,
1136 testEntry
.GetDateTime() ==
1137 wxFileName(path
).GetModificationTime());
1140 wxFFileInputStream
in(path
);
1141 CPPUNIT_ASSERT_MESSAGE(
1142 "entry not found in archive" + error_entry
, in
.Ok());
1144 size_t size
= in
.GetLength();
1145 wxCharBuffer
buf(size
);
1146 CPPUNIT_ASSERT_MESSAGE("Read" + error_context
,
1147 in
.Read(buf
.data(), size
).LastRead() == size
);
1148 CPPUNIT_ASSERT_MESSAGE("size check" + error_context
,
1149 testEntry
.GetSize() == size
);
1150 CPPUNIT_ASSERT_MESSAGE("data compare" + error_context
,
1151 memcmp(buf
.data(), testEntry
.GetData(), size
) == 0);
1154 VerifyDir(path
, rootlen
);
1158 m_testEntries
.erase(it
);
1160 while (dir
.GetNext(&name
));
1164 // test the simple iterators that give away ownership of an entry
1166 template <class Classes
>
1167 void ArchiveTestCase
<Classes
>::TestIterator(wxInputStream
& in
)
1169 typedef std::list
<EntryT
*> ArchiveCatalog
;
1170 typedef typename
ArchiveCatalog::iterator CatalogIter
;
1172 auto_ptr
<InputStreamT
> arc(m_factory
->NewStream(in
));
1175 #ifdef WXARC_MEMBER_TEMPLATES
1176 ArchiveCatalog
cat((IterT
)*arc
, IterT());
1179 for (IterT
i(*arc
); i
!= IterT(); ++i
)
1183 for (CatalogIter it
= cat
.begin(); it
!= cat
.end(); ++it
) {
1184 auto_ptr
<EntryT
> entry(*it
);
1185 count
+= m_testEntries
.count(entry
->GetName(wxPATH_UNIX
));
1188 CPPUNIT_ASSERT(m_testEntries
.size() == cat
.size());
1189 CPPUNIT_ASSERT(count
== cat
.size());
1192 // test the pair iterators that can be used to load a std::map or wxHashMap
1193 // these also give away ownership of entries
1195 template <class Classes
>
1196 void ArchiveTestCase
<Classes
>::TestPairIterator(wxInputStream
& in
)
1198 typedef std::map
<wxString
, EntryT
*> ArchiveCatalog
;
1199 typedef typename
ArchiveCatalog::iterator CatalogIter
;
1201 auto_ptr
<InputStreamT
> arc(m_factory
->NewStream(in
));
1204 #ifdef WXARC_MEMBER_TEMPLATES
1205 ArchiveCatalog
cat((PairIterT
)*arc
, PairIterT());
1208 for (PairIterT
i(*arc
); i
!= PairIterT(); ++i
)
1212 for (CatalogIter it
= cat
.begin(); it
!= cat
.end(); ++it
) {
1213 auto_ptr
<EntryT
> entry(it
->second
);
1214 count
+= m_testEntries
.count(entry
->GetName(wxPATH_UNIX
));
1217 CPPUNIT_ASSERT(m_testEntries
.size() == cat
.size());
1218 CPPUNIT_ASSERT(count
== cat
.size());
1221 // simple iterators using smart pointers, no need to worry about ownership
1223 template <class Classes
>
1224 void ArchiveTestCase
<Classes
>::TestSmartIterator(wxInputStream
& in
)
1226 typedef std::list
<Ptr
<EntryT
> > ArchiveCatalog
;
1227 typedef typename
ArchiveCatalog::iterator CatalogIter
;
1228 typedef wxArchiveIterator
<InputStreamT
, Ptr
<EntryT
> > Iter
;
1230 auto_ptr
<InputStreamT
> arc(m_factory
->NewStream(in
));
1232 #ifdef WXARC_MEMBER_TEMPLATES
1233 ArchiveCatalog
cat((Iter
)*arc
, Iter());
1236 for (Iter
i(*arc
); i
!= Iter(); ++i
)
1240 CPPUNIT_ASSERT(m_testEntries
.size() == cat
.size());
1242 for (CatalogIter it
= cat
.begin(); it
!= cat
.end(); ++it
)
1243 CPPUNIT_ASSERT(m_testEntries
.count((*it
)->GetName(wxPATH_UNIX
)));
1246 // pair iterator using smart pointers
1248 template <class Classes
>
1249 void ArchiveTestCase
<Classes
>::TestSmartPairIterator(wxInputStream
& in
)
1251 typedef std::map
<wxString
, Ptr
<EntryT
> > ArchiveCatalog
;
1252 typedef typename
ArchiveCatalog::iterator CatalogIter
;
1253 typedef wxArchiveIterator
<InputStreamT
,
1254 std::pair
<wxString
, Ptr
<EntryT
> > > PairIter
;
1256 auto_ptr
<InputStreamT
> arc(m_factory
->NewStream(in
));
1258 #ifdef WXARC_MEMBER_TEMPLATES
1259 ArchiveCatalog
cat((PairIter
)*arc
, PairIter());
1262 for (PairIter
i(*arc
); i
!= PairIter(); ++i
)
1266 CPPUNIT_ASSERT(m_testEntries
.size() == cat
.size());
1268 for (CatalogIter it
= cat
.begin(); it
!= cat
.end(); ++it
)
1269 CPPUNIT_ASSERT(m_testEntries
.count(it
->second
->GetName(wxPATH_UNIX
)));
1272 // try reading two entries at the same time
1274 template <class Classes
>
1275 void ArchiveTestCase
<Classes
>::ReadSimultaneous(TestInputStream
& in
)
1277 typedef std::map
<wxString
, Ptr
<EntryT
> > ArchiveCatalog
;
1278 typedef wxArchiveIterator
<InputStreamT
,
1279 std::pair
<wxString
, Ptr
<EntryT
> > > PairIter
;
1281 // create two archive input streams
1282 TestInputStream
in2(in
);
1283 auto_ptr
<InputStreamT
> arc(m_factory
->NewStream(in
));
1284 auto_ptr
<InputStreamT
> arc2(m_factory
->NewStream(in2
));
1287 #ifdef WXARC_MEMBER_TEMPLATES
1288 ArchiveCatalog
cat((PairIter
)*arc
, PairIter());
1291 for (PairIter
i(*arc
); i
!= PairIter(); ++i
)
1295 // the names of two entries to read
1296 const wxChar
*name
= _T("text/small");
1297 const wxChar
*name2
= _T("bin/bin1000");
1300 typename
ArchiveCatalog::iterator j
;
1301 CPPUNIT_ASSERT((j
= cat
.find(name
)) != cat
.end());
1302 CPPUNIT_ASSERT(arc
->OpenEntry(*j
->second
));
1303 CPPUNIT_ASSERT((j
= cat
.find(name2
)) != cat
.end());
1304 CPPUNIT_ASSERT(arc2
->OpenEntry(*j
->second
));
1306 // get pointers to the expected data
1307 TestEntries::iterator k
;
1308 CPPUNIT_ASSERT((k
= m_testEntries
.find(name
)) != m_testEntries
.end());
1309 TestEntry
*entry
= k
->second
;
1310 CPPUNIT_ASSERT((k
= m_testEntries
.find(name2
)) != m_testEntries
.end());
1311 TestEntry
*entry2
= k
->second
;
1313 size_t count
= 0, count2
= 0;
1314 size_t size
= entry
->GetSize(), size2
= entry2
->GetSize();
1315 const char *data
= entry
->GetData(), *data2
= entry2
->GetData();
1317 // read and check the two entries in parallel, character by character
1318 while (arc
->IsOk() || arc2
->IsOk()) {
1319 char ch
= arc
->GetC();
1320 if (arc
->LastRead() == 1) {
1321 CPPUNIT_ASSERT(count
< size
);
1322 CPPUNIT_ASSERT(ch
== data
[count
++]);
1324 char ch2
= arc2
->GetC();
1325 if (arc2
->LastRead() == 1) {
1326 CPPUNIT_ASSERT(count2
< size2
);
1327 CPPUNIT_ASSERT(ch2
== data2
[count2
++]);
1331 CPPUNIT_ASSERT(arc
->Eof());
1332 CPPUNIT_ASSERT(arc2
->Eof());
1333 CPPUNIT_ASSERT(count
== size
);
1334 CPPUNIT_ASSERT(count2
== size2
);
1337 // Nothing useful can be done with a generic notifier yet, so just test one
1340 template <class NotifierT
, class EntryT
>
1341 class ArchiveNotifier
: public NotifierT
1344 void OnEntryUpdated(EntryT
& WXUNUSED(entry
)) { }
1347 template <class Classes
>
1348 void ArchiveTestCase
<Classes
>::OnSetNotifier(EntryT
& entry
)
1350 static ArchiveNotifier
<NotifierT
, EntryT
> notifier
;
1351 entry
.SetNotifier(notifier
);
1355 ///////////////////////////////////////////////////////////////////////////////
1356 // ArchiveTestCase<ZipClasses> could be used directly, but instead this
1357 // derived class is used so that zip specific features can be tested.
1359 class ZipTestCase
: public ArchiveTestCase
<ZipClasses
>
1362 ZipTestCase(string name
,
1365 const wxString
& archiver
= wxEmptyString
,
1366 const wxString
& unarchiver
= wxEmptyString
)
1368 ArchiveTestCase
<ZipClasses
>(name
, id
, new wxZipClassFactory
,
1369 options
, archiver
, unarchiver
),
1374 void OnCreateArchive(wxZipOutputStream
& zip
);
1376 void OnArchiveExtracted(wxZipInputStream
& zip
, int expectedTotal
);
1378 void OnCreateEntry(wxZipOutputStream
& zip
,
1379 TestEntry
& testEntry
,
1382 void OnEntryExtracted(wxZipEntry
& entry
,
1383 const TestEntry
& testEntry
,
1384 wxZipInputStream
*arc
);
1386 void OnSetNotifier(EntryT
& entry
);
1392 void ZipTestCase::OnCreateArchive(wxZipOutputStream
& zip
)
1394 m_comment
<< _T("Comment for test ") << m_id
;
1395 zip
.SetComment(m_comment
);
1398 void ZipTestCase::OnArchiveExtracted(wxZipInputStream
& zip
, int expectedTotal
)
1400 CPPUNIT_ASSERT(zip
.GetComment() == m_comment
);
1401 CPPUNIT_ASSERT(zip
.GetTotalEntries() == expectedTotal
);
1404 void ZipTestCase::OnCreateEntry(wxZipOutputStream
& zip
,
1405 TestEntry
& testEntry
,
1408 zip
.SetLevel((m_id
+ m_count
) % 10);
1411 switch ((m_id
+ m_count
) % 5) {
1414 wxString comment
= _T("Comment for ") + entry
->GetName();
1415 entry
->SetComment(comment
);
1416 // lowercase the expected result, and the notifier should do
1417 // the same for the zip entries when ModifyArchive() runs
1418 testEntry
.SetComment(comment
.Lower());
1422 entry
->SetMethod(wxZIP_METHOD_STORE
);
1425 entry
->SetMethod(wxZIP_METHOD_DEFLATE
);
1428 entry
->SetIsText(testEntry
.IsText());
1434 void ZipTestCase::OnEntryExtracted(wxZipEntry
& entry
,
1435 const TestEntry
& testEntry
,
1436 wxZipInputStream
*arc
)
1438 // provide some context for the error message so that we know which
1439 // iteration of the loop we were on
1440 wxString name
= _T(" '") + entry
.GetName() + _T("'");
1441 string
error_entry(name
.mb_str());
1442 string
error_context(" failed for entry" + error_entry
);
1444 CPPUNIT_ASSERT_MESSAGE("GetComment" + error_context
,
1445 entry
.GetComment() == testEntry
.GetComment());
1447 // for seekable streams, GetNextEntry() doesn't read the local header so
1448 // call OpenEntry() to do it
1449 if (arc
&& (m_options
& PipeIn
) == 0 && entry
.IsDir())
1450 arc
->OpenEntry(entry
);
1452 CPPUNIT_ASSERT_MESSAGE("IsText" + error_context
,
1453 entry
.IsText() == testEntry
.IsText());
1455 CPPUNIT_ASSERT_MESSAGE("Extra/LocalExtra mismatch for entry" + error_entry
,
1456 (entry
.GetExtraLen() != 0 && entry
.GetLocalExtraLen() != 0) ||
1457 (entry
.GetExtraLen() == 0 && entry
.GetLocalExtraLen() == 0));
1460 // check the notifier mechanism by using it to fold the entry comments to
1463 class ZipNotifier
: public wxZipNotifier
1466 void OnEntryUpdated(wxZipEntry
& entry
);
1469 void ZipNotifier::OnEntryUpdated(wxZipEntry
& entry
)
1471 entry
.SetComment(entry
.GetComment().Lower());
1474 void ZipTestCase::OnSetNotifier(EntryT
& entry
)
1476 static ZipNotifier notifier
;
1477 entry
.SetNotifier(notifier
);
1481 ///////////////////////////////////////////////////////////////////////////////
1482 // 'zip - -' produces local headers without the size field set. This is a
1483 // case not covered by all the other tests, so this class tests it as a
1486 class ZipPipeTestCase
: public CppUnit::TestCase
1489 ZipPipeTestCase(string name
, int options
) :
1490 CppUnit::TestCase(name
), m_options(options
) { }
1497 void ZipPipeTestCase::runTest()
1499 TestOutputStream
out(m_options
);
1501 wxString testdata
= _T("test data to pipe through zip");
1502 wxString cmd
= _T("echo ") + testdata
+ _T(" | zip -q - -");
1505 PFileInputStream
in(cmd
);
1510 TestInputStream
in(out
);
1511 wxZipInputStream
zip(in
);
1513 auto_ptr
<wxZipEntry
> entry(zip
.GetNextEntry());
1514 CPPUNIT_ASSERT(entry
.get() != NULL
);
1516 if ((m_options
& PipeIn
) == 0)
1517 CPPUNIT_ASSERT(entry
->GetSize() != wxInvalidOffset
);
1520 size_t len
= zip
.Read(buf
, sizeof(buf
) - 1).LastRead();
1522 while (len
> 0 && buf
[len
- 1] <= 32)
1526 CPPUNIT_ASSERT(zip
.Eof());
1527 CPPUNIT_ASSERT(wxString(buf
, *wxConvCurrent
) == testdata
);
1531 ///////////////////////////////////////////////////////////////////////////////
1534 class ArchiveTestSuite
: public CppUnit::TestSuite
1538 static CppUnit::Test
*suite()
1539 { return (new ArchiveTestSuite
)->makeSuite(); }
1545 ArchiveTestSuite
*makeSuite();
1546 void AddCmd(wxArrayString
& cmdlist
, const wxString
& cmd
);
1547 bool IsInPath(const wxString
& cmd
);
1549 string
Description(const wxString
& type
,
1551 bool genericInterface
= false,
1552 const wxString
& archiver
= wxEmptyString
,
1553 const wxString
& unarchiver
= wxEmptyString
);
1556 ArchiveTestSuite::ArchiveTestSuite()
1557 : CppUnit::TestSuite("ArchiveTestSuite"),
1560 m_path
.AddEnvList(_T("PATH"));
1563 // add the command for an external archiver to the list, testing for it in
1566 void ArchiveTestSuite::AddCmd(wxArrayString
& cmdlist
, const wxString
& cmd
)
1568 if (cmdlist
.empty())
1569 cmdlist
.push_back(_T(""));
1571 cmdlist
.push_back(cmd
);
1574 bool ArchiveTestSuite::IsInPath(const wxString
& cmd
)
1576 wxString c
= cmd
.BeforeFirst(_T(' '));
1580 return !m_path
.FindValidPath(c
).empty();
1583 // make the test suite
1585 ArchiveTestSuite
*ArchiveTestSuite::makeSuite()
1587 typedef wxArrayString::iterator Iter
;
1588 wxArrayString zippers
;
1589 wxArrayString unzippers
;
1591 AddCmd(zippers
, _T("zip -qr %s *"));
1592 AddCmd(unzippers
, _T("unzip -q %s"));
1594 for (int genInterface
= 0; genInterface
< 2; genInterface
++)
1595 for (Iter i
= unzippers
.begin(); i
!= unzippers
.end(); ++i
)
1596 for (Iter j
= zippers
.begin(); j
!= zippers
.end(); ++j
)
1597 for (int options
= 0; options
<= AllOptions
; options
++)
1599 // unzip doesn't support piping in the zip
1600 if ((options
& PipeIn
) && !i
->empty())
1602 #ifdef WXARC_NO_POPEN
1603 // if no popen then can use piped output of zip
1604 if ((options
& PipeOut
) && !j
->empty())
1607 string name
= Description(_T("wxZip"), options
,
1608 genInterface
!= 0, *j
, *i
);
1611 addTest(new ArchiveTestCase
<ArchiveClasses
>(
1613 new wxZipClassFactory
,
1616 addTest(new ZipTestCase(name
, m_id
, options
, *j
, *i
));
1621 #ifndef WXARC_NO_POPEN
1622 // if have popen then can check the piped output of 'zip - -'
1623 if (IsInPath(_T("zip")))
1624 for (int options
= 0; options
<= PipeIn
; options
+= PipeIn
) {
1625 string name
= Description(_T("ZipPipeTestCase"), options
);
1626 addTest(new ZipPipeTestCase(name
, options
));
1634 // make a display string for the option bits
1636 string
ArchiveTestSuite::Description(const wxString
& type
,
1638 bool genericInterface
,
1639 const wxString
& archiver
,
1640 const wxString
& unarchiver
)
1643 descr
<< m_id
<< _T(" ");
1645 if (genericInterface
)
1646 descr
<< _T("wxArchive (") << type
<< _T(")");
1650 if (!archiver
.empty())
1651 descr
<< _T(" ") << archiver
.BeforeFirst(_T(' '));
1652 if (!unarchiver
.empty())
1653 descr
<< _T(" ") << unarchiver
.BeforeFirst(_T(' '));
1657 if ((options
& PipeIn
) != 0)
1658 optstr
+= _T("|PipeIn");
1659 if ((options
& PipeOut
) != 0)
1660 optstr
+= _T("|PipeOut");
1661 if ((options
& Stub
) != 0)
1662 optstr
+= _T("|Stub");
1663 if (!optstr
.empty())
1664 optstr
= _T(" (") + optstr
.substr(1) + _T(")");
1668 return (const char*)descr
.mb_str();
1671 // register in the unnamed registry so that these tests are run by default
1672 CPPUNIT_TEST_SUITE_REGISTRATION(ArchiveTestSuite
);
1674 // also include in it's own registry so that these tests can be run alone
1675 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(ArchiveTestSuite
, "ArchiveTestSuite");
1677 #endif // wxUSE_STREAMS