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 #include "wx/zipstrm.h"
25 #include "wx/mstream.h"
26 #include "wx/wfstream.h"
32 // Check whether member templates can be used
34 #if defined __GNUC__ && \
35 (__GNUC__ >= 3 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95))
36 # define WXARC_MEMBER_TEMPLATES
38 #if defined _MSC_VER && _MSC_VER >= 1310
39 # define WXARC_MEMBER_TEMPLATES
41 #if defined __BORLANDC__ && __BORLANDC__ >= 0x530
42 # define WXARC_MEMBER_TEMPLATES
44 #if defined __DMC__ && __DMC__ >= 0x832
45 # define WXARC_MEMBER_TEMPLATES
47 #if defined __MWERKS__ && __MWERKS__ >= 0x2200
48 # define WXARC_MEMBER_TEMPLATES
50 #if defined __HP_aCC && __HP_aCC > 33300
51 # define WXARC_MEMBER_TEMPLATES
53 #if defined __SUNPRO_CC && __SUNPRO_CC > 0x500
54 # define WXARC_MEMBER_TEMPLATES
58 ///////////////////////////////////////////////////////////////////////////////
59 // Bit flags for options for the tests
63 PipeIn
= 0x01, // input streams are non-seekable
64 PipeOut
= 0x02, // output streams are non-seekable
65 Stub
= 0x04, // the archive should be appended to a stub
70 ///////////////////////////////////////////////////////////////////////////////
71 // These structs are passed as the template parameter of the test case to
72 // specify a set of classes to use in the test. This allows either the generic
73 // wxArchiveXXX interface to be exercised or the specific interface for a
74 // particular archive format e.g. wxZipXXX.
78 typedef wxArchiveEntry EntryT
;
79 typedef wxArchiveInputStream InputStreamT
;
80 typedef wxArchiveOutputStream OutputStreamT
;
81 typedef wxArchiveClassFactory ClassFactoryT
;
82 typedef wxArchiveNotifier NotifierT
;
83 typedef wxArchiveIter IterT
;
84 typedef wxArchivePairIter PairIterT
;
89 typedef wxZipEntry EntryT
;
90 typedef wxZipInputStream InputStreamT
;
91 typedef wxZipOutputStream OutputStreamT
;
92 typedef wxZipClassFactory ClassFactoryT
;
93 typedef wxZipNotifier NotifierT
;
94 typedef wxZipIter IterT
;
95 typedef wxZipPairIter PairIterT
;
99 ///////////////////////////////////////////////////////////////////////////////
100 // A class to hold a test entry
105 TestEntry(const wxDateTime
& dt
, int len
, const char *data
);
106 ~TestEntry() { delete [] (char*) m_data
; }
108 wxDateTime
GetDateTime() const { return m_dt
; }
109 wxFileOffset
GetLength() const { return m_len
; }
110 size_t GetSize() const { return m_len
; }
111 const char *GetData() const { return m_data
; }
112 wxString
GetComment() const { return m_comment
; }
113 bool IsText() const { return m_isText
; }
115 void SetComment(const wxString
& comment
) { m_comment
= comment
; }
116 void SetDateTime(const wxDateTime
& dt
) { m_dt
= dt
; }
126 TestEntry::TestEntry(const wxDateTime
& dt
, int len
, const char *data
)
131 char *d
= new char[len
];
132 memcpy(d
, data
, len
);
135 for (int i
= 0; i
< len
&& m_isText
; i
++)
136 m_isText
= (signed char)m_data
[i
] > 0;
140 ///////////////////////////////////////////////////////////////////////////////
141 // TestOutputStream and TestInputStream are memory streams which can be
142 // seekable or non-seekable.
144 class TestOutputStream
: public wxOutputStream
147 TestOutputStream(int options
);
149 ~TestOutputStream() { delete [] m_data
; }
151 int GetOptions() const { return m_options
; }
152 wxFileOffset
GetLength() const { return m_size
; }
154 // gives away the data, this stream is then empty, and can be reused
155 void GetData(const char*& data
, size_t& size
);
157 enum { STUB_SIZE
= 2048, INITIAL_SIZE
= 0x18000, SEEK_LIMIT
= 0x100000 };
162 wxFileOffset
OnSysSeek(wxFileOffset pos
, wxSeekMode mode
);
163 wxFileOffset
OnSysTell() const;
164 size_t OnSysWrite(const void *buffer
, size_t size
);
173 TestOutputStream::TestOutputStream(int options
)
179 void TestOutputStream::Init()
186 if (m_options
& Stub
) {
187 wxCharBuffer
buf(STUB_SIZE
);
188 memset(buf
.data(), 0, STUB_SIZE
);
189 Write(buf
, STUB_SIZE
);
193 wxFileOffset
TestOutputStream::OnSysSeek(wxFileOffset pos
, wxSeekMode mode
)
195 if ((m_options
& PipeOut
) == 0) {
197 case wxFromStart
: break;
198 case wxFromCurrent
: pos
+= m_pos
; break;
199 case wxFromEnd
: pos
+= m_size
; break;
201 if (pos
< 0 || pos
> SEEK_LIMIT
)
202 return wxInvalidOffset
;
206 return wxInvalidOffset
;
209 wxFileOffset
TestOutputStream::OnSysTell() const
211 return (m_options
& PipeOut
) == 0 ? (wxFileOffset
)m_pos
: wxInvalidOffset
;
214 size_t TestOutputStream::OnSysWrite(const void *buffer
, size_t size
)
216 if (!IsOk() || !size
)
218 m_lasterror
= wxSTREAM_WRITE_ERROR
;
220 size_t newsize
= m_pos
+ size
;
221 wxCHECK(newsize
> m_pos
, 0);
223 if (m_capacity
< newsize
) {
224 size_t capacity
= m_capacity
? m_capacity
: INITIAL_SIZE
;
226 while (capacity
< newsize
) {
228 wxCHECK(capacity
> m_capacity
, 0);
231 char *buf
= new char[capacity
];
233 memcpy(buf
, m_data
, m_capacity
);
236 m_capacity
= capacity
;
239 memcpy(m_data
+ m_pos
, buffer
, size
);
243 m_lasterror
= wxSTREAM_NO_ERROR
;
248 void TestOutputStream::GetData(const char*& data
, size_t& size
)
253 if (m_options
& Stub
) {
257 if (size
> m_capacity
) {
259 memcpy(d
+ STUB_SIZE
, m_data
, m_size
);
263 memmove(d
+ STUB_SIZE
, d
, m_size
);
266 memset(d
, 0, STUB_SIZE
);
274 class TestInputStream
: public wxInputStream
277 // ctor takes the data from the output stream, which is then empty
278 TestInputStream(TestOutputStream
& out
) : m_data(NULL
) { SetData(out
); }
280 TestInputStream(const TestInputStream
& in
);
281 ~TestInputStream() { delete [] (char*) m_data
; }
284 wxFileOffset
GetLength() const { return m_size
; }
285 void SetData(TestOutputStream
& out
);
288 wxFileOffset
OnSysSeek(wxFileOffset pos
, wxSeekMode mode
);
289 wxFileOffset
OnSysTell() const;
290 size_t OnSysRead(void *buffer
, size_t size
);
298 TestInputStream::TestInputStream(const TestInputStream
& in
)
299 : m_options(in
.m_options
),
303 char *p
= new char[m_size
];
304 memcpy(p
, in
.m_data
, m_size
);
308 void TestInputStream::Rewind()
310 if ((m_options
& Stub
) && (m_options
& PipeIn
))
311 m_pos
= TestOutputStream::STUB_SIZE
* 2;
323 void TestInputStream::SetData(TestOutputStream
& out
)
325 delete [] (char*) m_data
;
326 m_options
= out
.GetOptions();
327 out
.GetData(m_data
, m_size
);
332 wxFileOffset
TestInputStream::OnSysSeek(wxFileOffset pos
, wxSeekMode mode
)
334 if ((m_options
& PipeIn
) == 0) {
336 case wxFromStart
: break;
337 case wxFromCurrent
: pos
+= m_pos
; break;
338 case wxFromEnd
: pos
+= m_size
; break;
340 if (pos
< 0 || pos
> TestOutputStream::SEEK_LIMIT
)
341 return wxInvalidOffset
;
345 return wxInvalidOffset
;
348 wxFileOffset
TestInputStream::OnSysTell() const
350 return (m_options
& PipeIn
) == 0 ? (wxFileOffset
)m_pos
: wxInvalidOffset
;
353 size_t TestInputStream::OnSysRead(void *buffer
, size_t size
)
355 if (!IsOk() || !size
)
357 if (m_size
<= m_pos
) {
358 m_lasterror
= wxSTREAM_EOF
;
362 if (m_size
- m_pos
< size
)
363 size
= m_size
- m_pos
;
364 memcpy(buffer
, m_data
+ m_pos
, size
);
370 ///////////////////////////////////////////////////////////////////////////////
371 // minimal non-intrusive reference counting pointer for testing the iterators
373 template <class T
> class Ptr
376 explicit Ptr(T
* p
= NULL
) : m_p(p
), m_count(new int) { *m_count
= 1; }
377 Ptr(const Ptr
& sp
) : m_p(sp
.m_p
), m_count(sp
.m_count
) { ++*m_count
; }
380 Ptr
& operator =(const Ptr
& sp
) {
384 m_count
= sp
.m_count
;
390 T
* get() const { return m_p
; }
391 T
* operator->() const { return m_p
; }
392 T
& operator*() const { return *m_p
; }
396 if (--*m_count
== 0) {
407 ///////////////////////////////////////////////////////////////////////////////
408 // Clean-up for temp directory
415 wxString
GetName() const { return m_tmp
; }
418 void RemoveDir(wxString
& path
);
425 wxString tmp
= wxFileName::CreateTempFileName(_T("arctest-"));
426 if (tmp
!= wxEmptyString
) {
428 m_original
= wxGetCwd();
429 CPPUNIT_ASSERT(wxMkdir(tmp
, 0700));
431 CPPUNIT_ASSERT(wxSetWorkingDirectory(tmp
));
437 if (m_tmp
!= wxEmptyString
) {
438 wxSetWorkingDirectory(m_original
);
443 void TempDir::RemoveDir(wxString
& path
)
445 wxCHECK_RET(!m_tmp
.empty() && path
.substr(0, m_tmp
.length()) == m_tmp
,
446 _T("remove '") + path
+ _T("' fails safety check"));
448 const wxChar
*files
[] = {
458 _T("zero/zero32768"),
459 _T("zero/zero16385"),
464 const wxChar
*dirs
[] = {
465 _T("text/"), _T("bin/"), _T("zero/"), _T("empty/")
468 wxString tmp
= m_tmp
+ wxFileName::GetPathSeparator();
471 for (i
= 0; i
< WXSIZEOF(files
); i
++)
472 wxRemoveFile(tmp
+ wxFileName(files
[i
], wxPATH_UNIX
).GetFullPath());
474 for (i
= 0; i
< WXSIZEOF(dirs
); i
++)
475 wxRmdir(tmp
+ wxFileName(dirs
[i
], wxPATH_UNIX
).GetFullPath());
478 wxLogSysError(_T("can't remove temporary dir '%s'"), m_tmp
.c_str());
482 ///////////////////////////////////////////////////////////////////////////////
483 // wxFFile streams for piping to/from an external program
485 #if defined __UNIX__ || defined __MINGW32__
486 # define WXARC_popen popen
487 # define WXARC_pclose pclose
488 #elif defined _MSC_VER || defined __BORLANDC__
489 # define WXARC_popen _popen
490 # define WXARC_pclose _pclose
492 # define WXARC_NO_POPEN
493 # define WXARC_popen(cmd, type) NULL
494 # define WXARC_pclose(fp)
503 class PFileInputStream
: public wxFFileInputStream
506 PFileInputStream(const wxString
& cmd
) :
507 wxFFileInputStream(WXARC_popen(cmd
.mb_str(), "r" WXARC_b
)) { }
509 { WXARC_pclose(m_file
->fp()); m_file
->Detach(); }
512 class PFileOutputStream
: public wxFFileOutputStream
515 PFileOutputStream(const wxString
& cmd
) :
516 wxFFileOutputStream(WXARC_popen(cmd
.mb_str(), "w" WXARC_b
)) { }
518 { WXARC_pclose(m_file
->fp()); m_file
->Detach(); }
522 ///////////////////////////////////////////////////////////////////////////////
525 template <class Classes
>
526 class ArchiveTestCase
: public CppUnit::TestCase
529 ArchiveTestCase(const wxString
& name
,
531 typename
Classes::ClassFactoryT
*factory
,
533 const wxString
& archiver
= wxEmptyString
,
534 const wxString
& unarchiver
= wxEmptyString
);
539 // the classes to test
540 typedef typename
Classes::EntryT EntryT
;
541 typedef typename
Classes::InputStreamT InputStreamT
;
542 typedef typename
Classes::OutputStreamT OutputStreamT
;
543 typedef typename
Classes::ClassFactoryT ClassFactoryT
;
544 typedef typename
Classes::NotifierT NotifierT
;
545 typedef typename
Classes::IterT IterT
;
546 typedef typename
Classes::PairIterT PairIterT
;
548 // the entry point for the test
551 // create the test data
552 void CreateTestData();
553 TestEntry
& Add(const char *name
, const char *data
, int len
= -1);
554 TestEntry
& Add(const char *name
, int len
= 0, int value
= EOF
);
556 // 'archive up' the test data
557 void CreateArchive(wxOutputStream
& out
);
558 void CreateArchive(wxOutputStream
& out
, const wxString
& archiver
);
560 // perform various modifications on the archive
561 void ModifyArchive(wxInputStream
& in
, wxOutputStream
& out
);
563 // extract the archive and verify its contents
564 void ExtractArchive(wxInputStream
& in
);
565 void ExtractArchive(wxInputStream
& in
, const wxString
& unarchiver
);
566 void VerifyDir(wxString
& path
, size_t rootlen
= 0);
568 // tests for the iterators
569 void TestIterator(wxInputStream
& in
);
570 void TestPairIterator(wxInputStream
& in
);
571 void TestSmartIterator(wxInputStream
& in
);
572 void TestSmartPairIterator(wxInputStream
& in
);
574 // try reading two entries at the same time
575 void ReadSimultaneous(TestInputStream
& in
);
578 virtual void OnCreateArchive(OutputStreamT
& WXUNUSED(arc
)) { }
579 virtual void OnSetNotifier(EntryT
& entry
);
581 virtual void OnArchiveExtracted(InputStreamT
& WXUNUSED(arc
),
582 int WXUNUSED(expectedTotal
)) { }
584 virtual void OnCreateEntry( OutputStreamT
& WXUNUSED(arc
),
585 TestEntry
& WXUNUSED(testEntry
),
586 EntryT
*entry
= NULL
) { (void)entry
; }
588 virtual void OnEntryExtracted( EntryT
& WXUNUSED(entry
),
589 const TestEntry
& WXUNUSED(testEntry
),
590 InputStreamT
*arc
= NULL
) { (void)arc
; }
592 typedef std::map
<wxString
, TestEntry
*> TestEntries
;
593 TestEntries m_testEntries
; // test data
594 std::auto_ptr
<ClassFactoryT
> m_factory
; // factory to make classes
595 int m_options
; // test options
596 wxDateTime m_timeStamp
; // timestamp to give test entries
597 int m_id
; // select between the possibilites
598 wxString m_archiver
; // external archiver
599 wxString m_unarchiver
; // external unarchiver
602 template <class Classes
>
603 ArchiveTestCase
<Classes
>::ArchiveTestCase(const wxString
& name
,
605 typename
Classes::ClassFactoryT
*factory
,
607 const wxString
& archiver
,
608 const wxString
& unarchiver
)
609 : CppUnit::TestCase(std::string(name
.mb_str())),
612 m_timeStamp(1, wxDateTime::Mar
, 2005, 12, 0),
614 m_archiver(archiver
),
615 m_unarchiver(unarchiver
)
619 template <class Classes
>
620 ArchiveTestCase
<Classes
>::~ArchiveTestCase()
622 TestEntries::iterator it
;
623 for (it
= m_testEntries
.begin(); it
!= m_testEntries
.end(); ++it
)
627 template <class Classes
>
628 void ArchiveTestCase
<Classes
>::runTest()
630 TestOutputStream
out(m_options
);
634 if (m_archiver
.empty())
637 CreateArchive(out
, m_archiver
);
639 // check archive could be created
640 CPPUNIT_ASSERT(out
.GetLength() > 0);
642 TestInputStream
in(out
);
646 TestPairIterator(in
);
648 TestSmartIterator(in
);
650 TestSmartPairIterator(in
);
653 if ((m_options
& PipeIn
) == 0) {
654 ReadSimultaneous(in
);
658 ModifyArchive(in
, out
);
661 if (m_unarchiver
.empty())
664 ExtractArchive(in
, m_unarchiver
);
666 // check that all the test entries were found in the archive
667 CPPUNIT_ASSERT(m_testEntries
.empty());
670 template <class Classes
>
671 void ArchiveTestCase
<Classes
>::CreateTestData()
674 Add("text/empty", "");
675 Add("text/small", "Small text file for testing\n"
676 "archive streams in wxWidgets\n");
679 Add("bin/bin1000", 1000);
680 Add("bin/bin4095", 4095);
681 Add("bin/bin4096", 4096);
682 Add("bin/bin4097", 4097);
683 Add("bin/bin16384", 16384);
686 Add("zero/zero5", 5, 0);
687 Add("zero/zero1024", 1024, 109);
688 Add("zero/zero32768", 32768, 106);
689 Add("zero/zero16385", 16385, 119);
694 template <class Classes
>
695 TestEntry
& ArchiveTestCase
<Classes
>::Add(const char *name
,
701 TestEntry
*& entry
= m_testEntries
[wxString(name
, *wxConvCurrent
)];
702 wxASSERT(entry
== NULL
);
703 entry
= new TestEntry(m_timeStamp
, len
, data
);
704 m_timeStamp
+= wxTimeSpan(0, 1, 30);
708 template <class Classes
>
709 TestEntry
& ArchiveTestCase
<Classes
>::Add(const char *name
,
713 wxCharBuffer
buf(len
);
714 for (int i
= 0; i
< len
; i
++)
715 buf
.data()[i
] = value
== EOF
? rand() : value
;
716 return Add(name
, buf
, len
);
719 // Create an archive using the wx archive classes, write it to 'out'
721 template <class Classes
>
722 void ArchiveTestCase
<Classes
>::CreateArchive(wxOutputStream
& out
)
724 std::auto_ptr
<OutputStreamT
> arc(m_factory
->NewStream(out
));
725 TestEntries::iterator it
;
727 OnCreateArchive(*arc
);
729 // We want to try creating entries in various different ways, 'choices'
730 // is just a number used to select between all the various possibilities.
733 for (it
= m_testEntries
.begin(); it
!= m_testEntries
.end(); ++it
) {
735 TestEntry
& testEntry
= *it
->second
;
736 wxString name
= it
->first
;
738 // It should be possible to create a directory entry just by supplying
739 // a name that looks like a directory, or alternatively any old name
740 // can be identified as a directory using SetIsDir or PutNextDirEntry
741 bool setIsDir
= name
.Last() == _T('/') && (choices
& 1);
743 name
.erase(name
.length() - 1);
745 // provide some context for the error message so that we know which
746 // iteration of the loop we were on
747 std::string
error_entry((_T(" '") + name
+ _T("'")).mb_str());
748 std::string
error_context(" failed for entry" + error_entry
);
750 if ((choices
& 2) || testEntry
.IsText()) {
751 // try PutNextEntry(EntryT *pEntry)
752 std::auto_ptr
<EntryT
> entry(m_factory
->NewEntry());
753 entry
->SetName(name
, wxPATH_UNIX
);
756 entry
->SetDateTime(testEntry
.GetDateTime());
757 entry
->SetSize(testEntry
.GetLength());
758 OnCreateEntry(*arc
, testEntry
, entry
.get());
759 CPPUNIT_ASSERT_MESSAGE("PutNextEntry" + error_context
,
760 arc
->PutNextEntry(entry
.release()));
763 // try the convenience methods
764 OnCreateEntry(*arc
, testEntry
);
766 CPPUNIT_ASSERT_MESSAGE("PutNextDirEntry" + error_context
,
767 arc
->PutNextDirEntry(name
, testEntry
.GetDateTime()));
769 CPPUNIT_ASSERT_MESSAGE("PutNextEntry" + error_context
,
770 arc
->PutNextEntry(name
, testEntry
.GetDateTime(),
771 testEntry
.GetLength()));
774 if (name
.Last() != _T('/')) {
775 // for non-dirs write the data
776 arc
->Write(testEntry
.GetData(), testEntry
.GetSize());
777 CPPUNIT_ASSERT_MESSAGE("LastWrite check" + error_context
,
778 arc
->LastWrite() == testEntry
.GetSize());
779 // should work with or without explicit CloseEntry
781 CPPUNIT_ASSERT_MESSAGE("CloseEntry" + error_context
,
785 CPPUNIT_ASSERT_MESSAGE("IsOk" + error_context
, arc
->IsOk());
788 // should work with or without explicit Close
790 CPPUNIT_ASSERT(arc
->Close());
793 // Create an archive using an external archive program
795 template <class Classes
>
796 void ArchiveTestCase
<Classes
>::CreateArchive(wxOutputStream
& out
,
797 const wxString
& archiver
)
799 // for an external archiver the test data need to be written to
804 TestEntries::iterator i
;
805 for (i
= m_testEntries
.begin(); i
!= m_testEntries
.end(); ++i
) {
806 wxFileName
fn(i
->first
, wxPATH_UNIX
);
807 TestEntry
& entry
= *i
->second
;
810 fn
.Mkdir(0777, wxPATH_MKDIR_FULL
);
812 wxFileName::Mkdir(fn
.GetPath(), 0777, wxPATH_MKDIR_FULL
);
813 wxFFileOutputStream
fileout(fn
.GetFullPath());
814 fileout
.Write(entry
.GetData(), entry
.GetSize());
818 for (i
= m_testEntries
.begin(); i
!= m_testEntries
.end(); ++i
) {
819 wxFileName
fn(i
->first
, wxPATH_UNIX
);
820 TestEntry
& entry
= *i
->second
;
821 wxDateTime dt
= entry
.GetDateTime();
824 entry
.SetDateTime(wxDateTime());
827 fn
.SetTimes(NULL
, &dt
, NULL
);
830 if ((m_options
& PipeOut
) == 0) {
831 wxFileName
fn(tmpdir
.GetName());
832 fn
.SetExt(_T("arc"));
833 wxString tmparc
= fn
.GetFullPath();
835 // call the archiver to create an archive file
836 system(wxString::Format(archiver
, tmparc
.c_str()).mb_str());
838 // then load the archive file
840 wxFFileInputStream
in(tmparc
);
845 wxRemoveFile(tmparc
);
848 // for the non-seekable test, have the archiver output to "-"
849 // and read the archive via a pipe
850 PFileInputStream
in(wxString::Format(archiver
, _T("-")));
856 // Do a standard set of modification on an archive, delete an entry,
857 // rename an entry and add an entry
859 template <class Classes
>
860 void ArchiveTestCase
<Classes
>::ModifyArchive(wxInputStream
& in
,
863 std::auto_ptr
<InputStreamT
> arcIn(m_factory
->NewStream(in
));
864 std::auto_ptr
<OutputStreamT
> arcOut(m_factory
->NewStream(out
));
865 std::auto_ptr
<EntryT
> entry
;
867 const wxString deleteName
= _T("bin/bin1000");
868 const wxString renameFrom
= _T("zero/zero1024");
869 const wxString renameTo
= _T("zero/newname");
870 const wxString newName
= _T("newfile");
871 const char *newData
= "New file added as a test\n";
873 arcOut
->CopyArchiveMetaData(*arcIn
);
875 while (entry
.reset(arcIn
->GetNextEntry()), entry
.get() != NULL
) {
876 OnSetNotifier(*entry
);
877 wxString name
= entry
->GetName(wxPATH_UNIX
);
879 // provide some context for the error message so that we know which
880 // iteration of the loop we were on
881 std::string
error_entry((_T(" '") + name
+ _T("'")).mb_str());
882 std::string
error_context(" failed for entry" + error_entry
);
884 if (name
== deleteName
) {
885 TestEntries::iterator it
= m_testEntries
.find(name
);
886 CPPUNIT_ASSERT_MESSAGE(
887 "deletion failed (already deleted?) for" + error_entry
,
888 it
!= m_testEntries
.end());
889 TestEntry
*p
= it
->second
;
890 m_testEntries
.erase(it
);
894 if (name
== renameFrom
) {
895 entry
->SetName(renameTo
);
896 TestEntries::iterator it
= m_testEntries
.find(renameFrom
);
897 CPPUNIT_ASSERT_MESSAGE(
898 "rename failed (already renamed?) for" + error_entry
,
899 it
!= m_testEntries
.end());
900 TestEntry
*p
= it
->second
;
901 m_testEntries
.erase(it
);
902 m_testEntries
[renameTo
] = p
;
905 CPPUNIT_ASSERT_MESSAGE("CopyEntry" + error_context
,
906 arcOut
->CopyEntry(entry
.release(), *arcIn
));
910 // check that the deletion and rename were done
911 CPPUNIT_ASSERT(m_testEntries
.count(deleteName
) == 0);
912 CPPUNIT_ASSERT(m_testEntries
.count(renameFrom
) == 0);
913 CPPUNIT_ASSERT(m_testEntries
.count(renameTo
) == 1);
915 // check that the end of the input archive was reached without error
916 CPPUNIT_ASSERT(arcIn
->Eof());
918 // try adding a new entry
919 TestEntry
& testEntry
= Add(newName
.mb_str(), newData
);
920 entry
.reset(m_factory
->NewEntry());
921 entry
->SetName(newName
);
922 entry
->SetDateTime(testEntry
.GetDateTime());
923 entry
->SetSize(testEntry
.GetLength());
924 OnCreateEntry(*arcOut
, testEntry
, entry
.get());
925 OnSetNotifier(*entry
);
926 CPPUNIT_ASSERT(arcOut
->PutNextEntry(entry
.release()));
927 CPPUNIT_ASSERT(arcOut
->Write(newData
, strlen(newData
)).IsOk());
929 // should work with or without explicit Close
931 CPPUNIT_ASSERT(arcOut
->Close());
934 // Extract an archive using the wx archive classes
936 template <class Classes
>
937 void ArchiveTestCase
<Classes
>::ExtractArchive(wxInputStream
& in
)
939 typedef Ptr
<EntryT
> EntryPtr
;
940 typedef std::list
<EntryPtr
> Entries
;
941 typedef typename
Entries::iterator EntryIter
;
943 std::auto_ptr
<InputStreamT
> arc(m_factory
->NewStream(in
));
944 int expectedTotal
= m_testEntries
.size();
948 if ((m_options
& PipeIn
) == 0)
949 OnArchiveExtracted(*arc
, expectedTotal
);
951 while (entry
= EntryPtr(arc
->GetNextEntry()), entry
.get() != NULL
) {
952 wxString name
= entry
->GetName(wxPATH_UNIX
);
954 // provide some context for the error message so that we know which
955 // iteration of the loop we were on
956 std::string
error_entry((_T(" '") + name
+ _T("'")).mb_str());
957 std::string
error_context(" failed for entry" + error_entry
);
959 TestEntries::iterator it
= m_testEntries
.find(name
);
960 CPPUNIT_ASSERT_MESSAGE(
961 "archive contains an entry that shouldn't be there" + error_entry
,
962 it
!= m_testEntries
.end());
964 const TestEntry
& testEntry
= *it
->second
;
966 wxDateTime dt
= testEntry
.GetDateTime();
968 CPPUNIT_ASSERT_MESSAGE("timestamp check" + error_context
,
969 dt
== entry
->GetDateTime());
971 // non-seekable entries are allowed to have GetSize == wxInvalidOffset
972 // until the end of the entry's data has been read past
973 CPPUNIT_ASSERT_MESSAGE("entry size check" + error_context
,
974 testEntry
.GetLength() == entry
->GetSize() ||
975 ((m_options
& PipeIn
) != 0 && entry
->GetSize() == wxInvalidOffset
));
976 CPPUNIT_ASSERT_MESSAGE(
977 "arc->GetLength() == entry->GetSize()" + error_context
,
978 arc
->GetLength() == entry
->GetSize());
980 if (name
.Last() != _T('/'))
982 CPPUNIT_ASSERT_MESSAGE("!IsDir" + error_context
,
984 wxCharBuffer
buf(testEntry
.GetSize() + 1);
985 CPPUNIT_ASSERT_MESSAGE("Read until Eof" + error_context
,
986 arc
->Read(buf
.data(), testEntry
.GetSize() + 1).Eof());
987 CPPUNIT_ASSERT_MESSAGE("LastRead check" + error_context
,
988 arc
->LastRead() == testEntry
.GetSize());
989 CPPUNIT_ASSERT_MESSAGE("data compare" + error_context
,
990 !memcmp(buf
.data(), testEntry
.GetData(), testEntry
.GetSize()));
992 CPPUNIT_ASSERT_MESSAGE("IsDir" + error_context
, entry
->IsDir());
995 // GetSize() must return the right result in all cases after all the
996 // data has been read
997 CPPUNIT_ASSERT_MESSAGE("entry size check" + error_context
,
998 testEntry
.GetLength() == entry
->GetSize());
999 CPPUNIT_ASSERT_MESSAGE(
1000 "arc->GetLength() == entry->GetSize()" + error_context
,
1001 arc
->GetLength() == entry
->GetSize());
1003 if ((m_options
& PipeIn
) == 0) {
1004 OnEntryExtracted(*entry
, testEntry
, arc
.get());
1006 m_testEntries
.erase(it
);
1008 entries
.push_back(entry
);
1012 // check that the end of the input archive was reached without error
1013 CPPUNIT_ASSERT(arc
->Eof());
1015 // for non-seekable streams these data are only guaranteed to be
1016 // available once the end of the archive has been reached
1017 if (m_options
& PipeIn
) {
1018 for (EntryIter i
= entries
.begin(); i
!= entries
.end(); ++i
) {
1019 wxString name
= (*i
)->GetName(wxPATH_UNIX
);
1020 TestEntries::iterator j
= m_testEntries
.find(name
);
1021 OnEntryExtracted(**i
, *j
->second
);
1023 m_testEntries
.erase(j
);
1025 OnArchiveExtracted(*arc
, expectedTotal
);
1029 // Extract an archive using an external unarchive program
1031 template <class Classes
>
1032 void ArchiveTestCase
<Classes
>::ExtractArchive(wxInputStream
& in
,
1033 const wxString
& unarchiver
)
1035 // for an external unarchiver, unarchive to a tempdir
1038 if ((m_options
& PipeIn
) == 0) {
1039 wxFileName
fn(tmpdir
.GetName());
1040 fn
.SetExt(_T("arc"));
1041 wxString tmparc
= fn
.GetFullPath();
1043 if (m_options
& Stub
)
1044 in
.SeekI(TestOutputStream::STUB_SIZE
* 2);
1046 // write the archive to a temporary file
1048 wxFFileOutputStream
out(tmparc
);
1054 system(wxString::Format(unarchiver
, tmparc
.c_str()).mb_str());
1055 wxRemoveFile(tmparc
);
1058 // for the non-seekable test, have the archiver extract "-" and
1059 // feed it the archive via a pipe
1060 PFileOutputStream
out(wxString::Format(unarchiver
, _T("-")));
1065 wxString dir
= tmpdir
.GetName();
1069 // Verifies the files produced by an external unarchiver are as expected
1071 template <class Classes
>
1072 void ArchiveTestCase
<Classes
>::VerifyDir(wxString
& path
, size_t rootlen
/*=0*/)
1075 path
+= wxFileName::GetPathSeparator();
1076 int pos
= path
.length();
1082 if (dir
.Open(path
) && dir
.GetFirst(&name
)) {
1084 path
.replace(pos
, wxString::npos
, name
);
1085 name
= m_factory
->GetInternalName(
1086 path
.substr(rootlen
, wxString::npos
));
1088 bool isDir
= wxDirExists(path
);
1092 // provide some context for the error message so that we know which
1093 // iteration of the loop we were on
1094 std::string
error_entry((_T(" '") + name
+ _T("'")).mb_str());
1095 std::string
error_context(" failed for entry" + error_entry
);
1097 TestEntries::iterator it
= m_testEntries
.find(name
);
1098 CPPUNIT_ASSERT_MESSAGE(
1099 "archive contains an entry that shouldn't be there"
1101 it
!= m_testEntries
.end());
1103 const TestEntry
& testEntry
= *it
->second
;
1106 CPPUNIT_ASSERT_MESSAGE("timestamp check" + error_context
,
1107 testEntry
.GetDateTime() ==
1108 wxFileName(path
).GetModificationTime());
1111 wxFFileInputStream
in(path
);
1112 CPPUNIT_ASSERT_MESSAGE(
1113 "entry not found in archive" + error_entry
, in
.Ok());
1115 size_t size
= in
.GetLength();
1116 wxCharBuffer
buf(size
);
1117 CPPUNIT_ASSERT_MESSAGE("Read" + error_context
,
1118 in
.Read(buf
.data(), size
).LastRead() == size
);
1119 CPPUNIT_ASSERT_MESSAGE("size check" + error_context
,
1120 testEntry
.GetSize() == size
);
1121 CPPUNIT_ASSERT_MESSAGE("data compare" + error_context
,
1122 memcmp(buf
.data(), testEntry
.GetData(), size
) == 0);
1125 VerifyDir(path
, rootlen
);
1129 m_testEntries
.erase(it
);
1131 while (dir
.GetNext(&name
));
1135 // test the simple iterators that give away ownership of an entry
1137 template <class Classes
>
1138 void ArchiveTestCase
<Classes
>::TestIterator(wxInputStream
& in
)
1140 typedef std::list
<EntryT
*> ArchiveCatalog
;
1141 typedef typename
ArchiveCatalog::iterator CatalogIter
;
1143 std::auto_ptr
<InputStreamT
> arc(m_factory
->NewStream(in
));
1146 #ifdef WXARC_MEMBER_TEMPLATES
1147 ArchiveCatalog
cat((IterT
)*arc
, IterT());
1150 for (IterT
i(*arc
); i
!= IterT(); ++i
)
1154 for (CatalogIter it
= cat
.begin(); it
!= cat
.end(); ++it
) {
1155 std::auto_ptr
<EntryT
> entry(*it
);
1156 count
+= m_testEntries
.count(entry
->GetName(wxPATH_UNIX
));
1159 CPPUNIT_ASSERT(m_testEntries
.size() == cat
.size());
1160 CPPUNIT_ASSERT(count
== cat
.size());
1163 // test the pair iterators that can be used to load a std::map or wxHashMap
1164 // these also give away ownership of entries
1166 template <class Classes
>
1167 void ArchiveTestCase
<Classes
>::TestPairIterator(wxInputStream
& in
)
1169 typedef std::map
<wxString
, EntryT
*> ArchiveCatalog
;
1170 typedef typename
ArchiveCatalog::iterator CatalogIter
;
1172 std::auto_ptr
<InputStreamT
> arc(m_factory
->NewStream(in
));
1175 #ifdef WXARC_MEMBER_TEMPLATES
1176 ArchiveCatalog
cat((PairIterT
)*arc
, PairIterT());
1179 for (PairIterT
i(*arc
); i
!= PairIterT(); ++i
)
1183 for (CatalogIter it
= cat
.begin(); it
!= cat
.end(); ++it
) {
1184 std::auto_ptr
<EntryT
> entry(it
->second
);
1185 count
+= m_testEntries
.count(entry
->GetName(wxPATH_UNIX
));
1188 CPPUNIT_ASSERT(m_testEntries
.size() == cat
.size());
1189 CPPUNIT_ASSERT(count
== cat
.size());
1192 // simple iterators using smart pointers, no need to worry about ownership
1194 template <class Classes
>
1195 void ArchiveTestCase
<Classes
>::TestSmartIterator(wxInputStream
& in
)
1197 typedef std::list
<Ptr
<EntryT
> > ArchiveCatalog
;
1198 typedef typename
ArchiveCatalog::iterator CatalogIter
;
1199 typedef wxArchiveIterator
<InputStreamT
, Ptr
<EntryT
> > Iter
;
1201 std::auto_ptr
<InputStreamT
> arc(m_factory
->NewStream(in
));
1203 #ifdef WXARC_MEMBER_TEMPLATES
1204 ArchiveCatalog
cat((Iter
)*arc
, Iter());
1207 for (Iter
i(*arc
); i
!= Iter(); ++i
)
1211 CPPUNIT_ASSERT(m_testEntries
.size() == cat
.size());
1213 for (CatalogIter it
= cat
.begin(); it
!= cat
.end(); ++it
)
1214 CPPUNIT_ASSERT(m_testEntries
.count((*it
)->GetName(wxPATH_UNIX
)));
1217 // pair iterator using smart pointers
1219 template <class Classes
>
1220 void ArchiveTestCase
<Classes
>::TestSmartPairIterator(wxInputStream
& in
)
1222 typedef std::map
<wxString
, Ptr
<EntryT
> > ArchiveCatalog
;
1223 typedef typename
ArchiveCatalog::iterator CatalogIter
;
1224 typedef wxArchiveIterator
<InputStreamT
,
1225 std::pair
<wxString
, Ptr
<EntryT
> > > PairIter
;
1227 std::auto_ptr
<InputStreamT
> arc(m_factory
->NewStream(in
));
1229 #ifdef WXARC_MEMBER_TEMPLATES
1230 ArchiveCatalog
cat((PairIter
)*arc
, PairIter());
1233 for (PairIter
i(*arc
); i
!= PairIter(); ++i
)
1237 CPPUNIT_ASSERT(m_testEntries
.size() == cat
.size());
1239 for (CatalogIter it
= cat
.begin(); it
!= cat
.end(); ++it
)
1240 CPPUNIT_ASSERT(m_testEntries
.count(it
->second
->GetName(wxPATH_UNIX
)));
1243 // try reading two entries at the same time
1245 template <class Classes
>
1246 void ArchiveTestCase
<Classes
>::ReadSimultaneous(TestInputStream
& in
)
1248 typedef std::map
<wxString
, Ptr
<EntryT
> > ArchiveCatalog
;
1249 typedef wxArchiveIterator
<InputStreamT
,
1250 std::pair
<wxString
, Ptr
<EntryT
> > > PairIter
;
1252 // create two archive input streams
1253 TestInputStream
in2(in
);
1254 std::auto_ptr
<InputStreamT
> arc(m_factory
->NewStream(in
));
1255 std::auto_ptr
<InputStreamT
> arc2(m_factory
->NewStream(in2
));
1258 #ifdef WXARC_MEMBER_TEMPLATES
1259 ArchiveCatalog
cat((PairIter
)*arc
, PairIter());
1262 for (PairIter
i(*arc
); i
!= PairIter(); ++i
)
1266 // the names of two entries to read
1267 const wxChar
*name
= _T("text/small");
1268 const wxChar
*name2
= _T("bin/bin1000");
1271 typename
ArchiveCatalog::iterator j
;
1272 CPPUNIT_ASSERT((j
= cat
.find(name
)) != cat
.end());
1273 CPPUNIT_ASSERT(arc
->OpenEntry(*j
->second
));
1274 CPPUNIT_ASSERT((j
= cat
.find(name2
)) != cat
.end());
1275 CPPUNIT_ASSERT(arc2
->OpenEntry(*j
->second
));
1277 // get pointers to the expected data
1278 TestEntries::iterator k
;
1279 CPPUNIT_ASSERT((k
= m_testEntries
.find(name
)) != m_testEntries
.end());
1280 TestEntry
*entry
= k
->second
;
1281 CPPUNIT_ASSERT((k
= m_testEntries
.find(name2
)) != m_testEntries
.end());
1282 TestEntry
*entry2
= k
->second
;
1284 size_t count
= 0, count2
= 0;
1285 size_t size
= entry
->GetSize(), size2
= entry2
->GetSize();
1286 const char *data
= entry
->GetData(), *data2
= entry2
->GetData();
1288 // read and check the two entries in parallel, character by character
1289 while (arc
->IsOk() || arc2
->IsOk()) {
1290 char ch
= arc
->GetC();
1291 if (arc
->LastRead() == 1) {
1292 CPPUNIT_ASSERT(count
< size
);
1293 CPPUNIT_ASSERT(ch
== data
[count
++]);
1295 char ch2
= arc2
->GetC();
1296 if (arc2
->LastRead() == 1) {
1297 CPPUNIT_ASSERT(count2
< size2
);
1298 CPPUNIT_ASSERT(ch2
== data2
[count2
++]);
1302 CPPUNIT_ASSERT(arc
->Eof());
1303 CPPUNIT_ASSERT(arc2
->Eof());
1304 CPPUNIT_ASSERT(count
== size
);
1305 CPPUNIT_ASSERT(count2
== size2
);
1308 // Nothing useful can be done with a generic notifier yet, so just test one
1311 template <class NotifierT
, class EntryT
>
1312 class ArchiveNotifier
: public NotifierT
1315 void OnEntryUpdated(EntryT
& WXUNUSED(entry
)) { }
1318 template <class Classes
>
1319 void ArchiveTestCase
<Classes
>::OnSetNotifier(EntryT
& entry
)
1321 static ArchiveNotifier
<NotifierT
, EntryT
> notifier
;
1322 entry
.SetNotifier(notifier
);
1326 ///////////////////////////////////////////////////////////////////////////////
1327 // ArchiveTestCase<ZipClasses> could be used directly, but instead this
1328 // derived class is used so that zip specific features can be tested.
1330 class ZipTestCase
: public ArchiveTestCase
<ZipClasses
>
1333 ZipTestCase(const wxString
& name
,
1336 const wxString
& archiver
= wxEmptyString
,
1337 const wxString
& unarchiver
= wxEmptyString
)
1339 ArchiveTestCase
<ZipClasses
>(name
, id
, new wxZipClassFactory
,
1340 options
, archiver
, unarchiver
),
1345 void OnCreateArchive(wxZipOutputStream
& zip
);
1347 void OnArchiveExtracted(wxZipInputStream
& zip
, int expectedTotal
);
1349 void OnCreateEntry(wxZipOutputStream
& zip
,
1350 TestEntry
& testEntry
,
1353 void OnEntryExtracted(wxZipEntry
& entry
,
1354 const TestEntry
& testEntry
,
1355 wxZipInputStream
*arc
);
1357 void OnSetNotifier(EntryT
& entry
);
1363 void ZipTestCase::OnCreateArchive(wxZipOutputStream
& zip
)
1365 m_comment
<< _T("Comment for test ") << m_id
;
1366 zip
.SetComment(m_comment
);
1369 void ZipTestCase::OnArchiveExtracted(wxZipInputStream
& zip
, int expectedTotal
)
1371 CPPUNIT_ASSERT(zip
.GetComment() == m_comment
);
1372 CPPUNIT_ASSERT(zip
.GetTotalEntries() == expectedTotal
);
1375 void ZipTestCase::OnCreateEntry(wxZipOutputStream
& zip
,
1376 TestEntry
& testEntry
,
1379 zip
.SetLevel((m_id
+ m_count
) % 10);
1382 switch ((m_id
+ m_count
) % 5) {
1385 wxString comment
= _T("Comment for ") + entry
->GetName();
1386 entry
->SetComment(comment
);
1387 // lowercase the expected result, and the notifier should do
1388 // the same for the zip entries when ModifyArchive() runs
1389 testEntry
.SetComment(comment
.Lower());
1393 entry
->SetMethod(wxZIP_METHOD_STORE
);
1396 entry
->SetMethod(wxZIP_METHOD_DEFLATE
);
1399 entry
->SetIsText(testEntry
.IsText());
1405 void ZipTestCase::OnEntryExtracted(wxZipEntry
& entry
,
1406 const TestEntry
& testEntry
,
1407 wxZipInputStream
*arc
)
1409 // provide some context for the error message so that we know which
1410 // iteration of the loop we were on
1411 std::string
error_entry((_T(" '") + entry
.GetName() + _T("'")).mb_str());
1412 std::string
error_context(" failed for entry" + error_entry
);
1414 CPPUNIT_ASSERT_MESSAGE("GetComment" + error_context
,
1415 entry
.GetComment() == testEntry
.GetComment());
1417 // for seekable streams, GetNextEntry() doesn't read the local header so
1418 // call OpenEntry() to do it
1419 if (arc
&& (m_options
& PipeIn
) == 0 && entry
.IsDir())
1420 arc
->OpenEntry(entry
);
1422 CPPUNIT_ASSERT_MESSAGE("IsText" + error_context
,
1423 entry
.IsText() == testEntry
.IsText());
1425 CPPUNIT_ASSERT_MESSAGE("Extra/LocalExtra mismatch for entry" + error_entry
,
1426 (entry
.GetExtraLen() != 0 && entry
.GetLocalExtraLen() != 0) ||
1427 (entry
.GetExtraLen() == 0 && entry
.GetLocalExtraLen() == 0));
1430 // check the notifier mechanism by using it to fold the entry comments to
1433 class ZipNotifier
: public wxZipNotifier
1436 void OnEntryUpdated(wxZipEntry
& entry
);
1439 void ZipNotifier::OnEntryUpdated(wxZipEntry
& entry
)
1441 entry
.SetComment(entry
.GetComment().Lower());
1444 void ZipTestCase::OnSetNotifier(EntryT
& entry
)
1446 static ZipNotifier notifier
;
1447 entry
.SetNotifier(notifier
);
1451 ///////////////////////////////////////////////////////////////////////////////
1452 // 'zip - -' produces local headers without the size field set. This is a
1453 // case not covered by all the other tests, so this class tests it as a
1456 class ZipPipeTestCase
: public CppUnit::TestCase
1459 ZipPipeTestCase(const wxString
& name
, int options
) :
1460 CppUnit::TestCase(std::string(name
.mb_str())), m_options(options
) { }
1467 void ZipPipeTestCase::runTest()
1469 TestOutputStream
out(m_options
);
1471 wxString testdata
= _T("test data to pipe through zip");
1472 wxString cmd
= _T("echo ") + testdata
+ _T(" | zip -q - -");
1475 PFileInputStream
in(cmd
);
1480 TestInputStream
in(out
);
1481 wxZipInputStream
zip(in
);
1483 std::auto_ptr
<wxZipEntry
> entry(zip
.GetNextEntry());
1484 CPPUNIT_ASSERT(entry
.get() != NULL
);
1486 if ((m_options
& PipeIn
) == 0)
1487 CPPUNIT_ASSERT(entry
->GetSize() != wxInvalidOffset
);
1490 size_t len
= zip
.Read(buf
, sizeof(buf
) - 1).LastRead();
1492 while (len
> 0 && buf
[len
- 1] <= 32)
1496 CPPUNIT_ASSERT(zip
.Eof());
1497 CPPUNIT_ASSERT(wxString(buf
, *wxConvCurrent
) == testdata
);
1501 ///////////////////////////////////////////////////////////////////////////////
1504 class ArchiveTestSuite
: public CppUnit::TestSuite
1508 static CppUnit::Test
*suite()
1509 { return (new ArchiveTestSuite
)->makeSuite(); }
1515 ArchiveTestSuite
*makeSuite();
1516 void AddCmd(wxArrayString
& cmdlist
, const wxString
& cmd
);
1517 bool IsInPath(const wxString
& cmd
);
1519 wxString
Description(const wxString
& type
,
1521 bool genericInterface
= false,
1522 const wxString
& archiver
= wxEmptyString
,
1523 const wxString
& unarchiver
= wxEmptyString
);
1526 ArchiveTestSuite::ArchiveTestSuite()
1527 : CppUnit::TestSuite("ArchiveTestSuite"),
1530 m_path
.AddEnvList(_T("PATH"));
1533 // add the command for an external archiver to the list, testing for it in
1536 void ArchiveTestSuite::AddCmd(wxArrayString
& cmdlist
, const wxString
& cmd
)
1538 if (cmdlist
.empty())
1539 cmdlist
.push_back(_T(""));
1541 cmdlist
.push_back(cmd
);
1544 bool ArchiveTestSuite::IsInPath(const wxString
& cmd
)
1546 wxString c
= cmd
.BeforeFirst(_T(' '));
1550 return !m_path
.FindValidPath(c
).empty();
1553 // make the test suite
1555 ArchiveTestSuite
*ArchiveTestSuite::makeSuite()
1557 typedef wxArrayString::iterator Iter
;
1558 wxArrayString zippers
;
1559 wxArrayString unzippers
;
1561 AddCmd(zippers
, _T("zip -qr %s *"));
1562 AddCmd(unzippers
, _T("unzip -q %s"));
1564 for (int genInterface
= 0; genInterface
< 2; genInterface
++)
1565 for (Iter i
= unzippers
.begin(); i
!= unzippers
.end(); ++i
)
1566 for (Iter j
= zippers
.begin(); j
!= zippers
.end(); ++j
)
1567 for (int options
= 0; options
<= AllOptions
; options
++)
1569 // unzip doesn't support piping in the zip
1570 if ((options
& PipeIn
) && !i
->empty())
1572 #ifdef WXARC_NO_POPEN
1573 // if no popen then can use piped output of zip
1574 if ((options
& PipeOut
) && !j
->empty())
1577 wxString name
= Description(_T("wxZip"), options
,
1578 genInterface
!= 0, *j
, *i
);
1581 addTest(new ArchiveTestCase
<ArchiveClasses
>(
1583 new wxZipClassFactory
,
1586 addTest(new ZipTestCase(name
, m_id
, options
, *j
, *i
));
1591 #ifndef WXARC_NO_POPEN
1592 // if have popen then can check the piped output of 'zip - -'
1593 if (IsInPath(_T("zip")))
1594 for (int options
= 0; options
<= PipeIn
; options
+= PipeIn
) {
1595 wxString name
= Description(_T("ZipPipeTestCase"), options
);
1596 addTest(new ZipPipeTestCase(name
, options
));
1604 // make a display string for the option bits
1606 wxString
ArchiveTestSuite::Description(const wxString
& type
,
1608 bool genericInterface
,
1609 const wxString
& archiver
,
1610 const wxString
& unarchiver
)
1613 descr
<< m_id
<< _T(" ");
1615 if (genericInterface
)
1616 descr
<< _T("wxArchive (") << type
<< _T(")");
1620 if (!archiver
.empty())
1621 descr
<< _T(" ") << archiver
.BeforeFirst(_T(' '));
1622 if (!unarchiver
.empty())
1623 descr
<< _T(" ") << unarchiver
.BeforeFirst(_T(' '));
1627 if ((options
& PipeIn
) != 0)
1628 optstr
+= _T("|PipeIn");
1629 if ((options
& PipeOut
) != 0)
1630 optstr
+= _T("|PipeOut");
1631 if ((options
& Stub
) != 0)
1632 optstr
+= _T("|Stub");
1633 if (!optstr
.empty())
1634 optstr
= _T(" (") + optstr
.substr(1) + _T(")");
1641 // register in the unnamed registry so that these tests are run by default
1642 CPPUNIT_TEST_SUITE_REGISTRATION(ArchiveTestSuite
);
1644 // also include in it's own registry so that these tests can be run alone
1645 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(ArchiveTestSuite
, "ArchiveTestSuite");
1647 #endif // wxUSE_STREAMS