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
: (size_t)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
)
310 m_options(in
.m_options
),
314 m_data
= new char[m_size
];
315 memcpy(m_data
, in
.m_data
, m_size
);
318 void TestInputStream::Rewind()
320 if ((m_options
& Stub
) && (m_options
& PipeIn
))
321 m_pos
= TestOutputStream::STUB_SIZE
* 2;
333 void TestInputStream::SetData(TestOutputStream
& out
)
336 m_options
= out
.GetOptions();
337 out
.GetData(m_data
, m_size
);
342 wxFileOffset
TestInputStream::OnSysSeek(wxFileOffset pos
, wxSeekMode mode
)
344 if ((m_options
& PipeIn
) == 0) {
346 case wxFromStart
: break;
347 case wxFromCurrent
: pos
+= m_pos
; break;
348 case wxFromEnd
: pos
+= m_size
; break;
350 if (pos
< 0 || pos
> TestOutputStream::SEEK_LIMIT
)
351 return wxInvalidOffset
;
355 return wxInvalidOffset
;
358 wxFileOffset
TestInputStream::OnSysTell() const
360 return (m_options
& PipeIn
) == 0 ? (wxFileOffset
)m_pos
: wxInvalidOffset
;
363 size_t TestInputStream::OnSysRead(void *buffer
, size_t size
)
365 if (!IsOk() || !size
)
367 if (m_size
<= m_pos
) {
368 m_lasterror
= wxSTREAM_EOF
;
372 if (m_size
- m_pos
< size
)
373 size
= m_size
- m_pos
;
374 memcpy(buffer
, m_data
+ m_pos
, size
);
380 ///////////////////////////////////////////////////////////////////////////////
381 // minimal non-intrusive reference counting pointer for testing the iterators
383 template <class T
> class Ptr
386 explicit Ptr(T
* p
= NULL
) : m_p(p
), m_count(new int) { *m_count
= 1; }
387 Ptr(const Ptr
& sp
) : m_p(sp
.m_p
), m_count(sp
.m_count
) { ++*m_count
; }
390 Ptr
& operator =(const Ptr
& sp
) {
394 m_count
= sp
.m_count
;
400 T
* get() const { return m_p
; }
401 T
* operator->() const { return m_p
; }
402 T
& operator*() const { return *m_p
; }
406 if (--*m_count
== 0) {
417 ///////////////////////////////////////////////////////////////////////////////
418 // Clean-up for temp directory
425 wxString
GetName() const { return m_tmp
; }
428 void RemoveDir(wxString
& path
);
435 wxString tmp
= wxFileName::CreateTempFileName(_T("arctest-"));
436 if (tmp
!= wxEmptyString
) {
438 m_original
= wxGetCwd();
439 CPPUNIT_ASSERT(wxMkdir(tmp
, 0700));
441 CPPUNIT_ASSERT(wxSetWorkingDirectory(tmp
));
447 if (m_tmp
!= wxEmptyString
) {
448 wxSetWorkingDirectory(m_original
);
453 void TempDir::RemoveDir(wxString
& path
)
455 wxCHECK_RET(!m_tmp
.empty() && path
.substr(0, m_tmp
.length()) == m_tmp
,
456 _T("remove '") + path
+ _T("' fails safety check"));
458 const wxChar
*files
[] = {
468 _T("zero/zero32768"),
469 _T("zero/zero16385"),
474 const wxChar
*dirs
[] = {
475 _T("text/"), _T("bin/"), _T("zero/"), _T("empty/")
478 wxString tmp
= m_tmp
+ wxFileName::GetPathSeparator();
481 for (i
= 0; i
< WXSIZEOF(files
); i
++)
482 wxRemoveFile(tmp
+ wxFileName(files
[i
], wxPATH_UNIX
).GetFullPath());
484 for (i
= 0; i
< WXSIZEOF(dirs
); i
++)
485 wxRmdir(tmp
+ wxFileName(dirs
[i
], wxPATH_UNIX
).GetFullPath());
488 wxLogSysError(_T("can't remove temporary dir '%s'"), m_tmp
.c_str());
492 ///////////////////////////////////////////////////////////////////////////////
493 // wxFFile streams for piping to/from an external program
495 #if defined __UNIX__ || defined __MINGW32__
496 # define WXARC_popen popen
497 # define WXARC_pclose pclose
498 #elif defined _MSC_VER || defined __BORLANDC__
499 # define WXARC_popen _popen
500 # define WXARC_pclose _pclose
502 # define WXARC_NO_POPEN
503 # define WXARC_popen(cmd, type) NULL
504 # define WXARC_pclose(fp)
513 class PFileInputStream
: public wxFFileInputStream
516 PFileInputStream(const wxString
& cmd
) :
517 wxFFileInputStream(WXARC_popen(cmd
.mb_str(), "r" WXARC_b
)) { }
519 { WXARC_pclose(m_file
->fp()); m_file
->Detach(); }
522 class PFileOutputStream
: public wxFFileOutputStream
525 PFileOutputStream(const wxString
& cmd
) :
526 wxFFileOutputStream(WXARC_popen(cmd
.mb_str(), "w" WXARC_b
)) { }
528 { WXARC_pclose(m_file
->fp()); m_file
->Detach(); }
532 ///////////////////////////////////////////////////////////////////////////////
535 template <class Classes
>
536 class ArchiveTestCase
: public CppUnit::TestCase
539 ArchiveTestCase(string name
,
541 wxArchiveClassFactory
*factory
,
543 const wxString
& archiver
= wxEmptyString
,
544 const wxString
& unarchiver
= wxEmptyString
);
549 // the classes to test
550 typedef typename
Classes::EntryT EntryT
;
551 typedef typename
Classes::InputStreamT InputStreamT
;
552 typedef typename
Classes::OutputStreamT OutputStreamT
;
553 typedef typename
Classes::ClassFactoryT ClassFactoryT
;
554 typedef typename
Classes::NotifierT NotifierT
;
555 typedef typename
Classes::IterT IterT
;
556 typedef typename
Classes::PairIterT PairIterT
;
558 // the entry point for the test
561 // create the test data
562 void CreateTestData();
563 TestEntry
& Add(const char *name
, const char *data
, int len
= -1);
564 TestEntry
& Add(const char *name
, int len
= 0, int value
= EOF
);
566 // 'archive up' the test data
567 void CreateArchive(wxOutputStream
& out
);
568 void CreateArchive(wxOutputStream
& out
, const wxString
& archiver
);
570 // perform various modifications on the archive
571 void ModifyArchive(wxInputStream
& in
, wxOutputStream
& out
);
573 // extract the archive and verify its contents
574 void ExtractArchive(wxInputStream
& in
);
575 void ExtractArchive(wxInputStream
& in
, const wxString
& unarchiver
);
576 void VerifyDir(wxString
& path
, size_t rootlen
= 0);
578 // tests for the iterators
579 void TestIterator(wxInputStream
& in
);
580 void TestPairIterator(wxInputStream
& in
);
581 void TestSmartIterator(wxInputStream
& in
);
582 void TestSmartPairIterator(wxInputStream
& in
);
584 // try reading two entries at the same time
585 void ReadSimultaneous(TestInputStream
& in
);
588 virtual void OnCreateArchive(OutputStreamT
& WXUNUSED(arc
)) { }
589 virtual void OnSetNotifier(EntryT
& entry
);
591 virtual void OnArchiveExtracted(InputStreamT
& WXUNUSED(arc
),
592 int WXUNUSED(expectedTotal
)) { }
594 virtual void OnCreateEntry( OutputStreamT
& WXUNUSED(arc
),
595 TestEntry
& WXUNUSED(testEntry
),
596 EntryT
*entry
= NULL
) { (void)entry
; }
598 virtual void OnEntryExtracted( EntryT
& WXUNUSED(entry
),
599 const TestEntry
& WXUNUSED(testEntry
),
600 InputStreamT
*arc
= NULL
) { (void)arc
; }
602 typedef std::map
<wxString
, TestEntry
*> TestEntries
;
603 TestEntries m_testEntries
; // test data
604 auto_ptr
<ClassFactoryT
> m_factory
; // factory to make classes
605 int m_options
; // test options
606 wxDateTime m_timeStamp
; // timestamp to give test entries
607 int m_id
; // select between the possibilites
608 wxString m_archiver
; // external archiver
609 wxString m_unarchiver
; // external unarchiver
613 // The only way I could get this to compile on VC++ 5.0 was to pass 'factory'
614 // as a wxArchiveFactory* then cast it, even then only with some ifdefing.
616 template <class Classes
>
617 ArchiveTestCase
<Classes
>::ArchiveTestCase(
620 wxArchiveClassFactory
*factory
,
622 const wxString
& archiver
,
623 const wxString
& unarchiver
)
625 CppUnit::TestCase(name
),
626 #if defined _MSC_VER && _MSC_VER < 1300
627 m_factory(dynamic_cast<Classes::ClassFactoryT
*>(factory
)),
629 m_factory(dynamic_cast<typename
Classes::ClassFactoryT
*>(factory
)),
632 m_timeStamp(1, wxDateTime::Mar
, 2005, 12, 0),
634 m_archiver(archiver
),
635 m_unarchiver(unarchiver
)
637 wxASSERT(m_factory
.get() != NULL
);
640 template <class Classes
>
641 ArchiveTestCase
<Classes
>::~ArchiveTestCase()
643 TestEntries::iterator it
;
644 for (it
= m_testEntries
.begin(); it
!= m_testEntries
.end(); ++it
)
648 template <class Classes
>
649 void ArchiveTestCase
<Classes
>::runTest()
651 TestOutputStream
out(m_options
);
655 if (m_archiver
.empty())
658 CreateArchive(out
, m_archiver
);
660 // check archive could be created
661 CPPUNIT_ASSERT(out
.GetLength() > 0);
663 TestInputStream
in(out
);
667 TestPairIterator(in
);
669 TestSmartIterator(in
);
671 TestSmartPairIterator(in
);
674 if ((m_options
& PipeIn
) == 0) {
675 ReadSimultaneous(in
);
679 ModifyArchive(in
, out
);
682 if (m_unarchiver
.empty())
685 ExtractArchive(in
, m_unarchiver
);
687 // check that all the test entries were found in the archive
688 CPPUNIT_ASSERT(m_testEntries
.empty());
691 template <class Classes
>
692 void ArchiveTestCase
<Classes
>::CreateTestData()
695 Add("text/empty", "");
696 Add("text/small", "Small text file for testing\n"
697 "archive streams in wxWidgets\n");
700 Add("bin/bin1000", 1000);
701 Add("bin/bin4095", 4095);
702 Add("bin/bin4096", 4096);
703 Add("bin/bin4097", 4097);
704 Add("bin/bin16384", 16384);
707 Add("zero/zero5", 5, 0);
708 Add("zero/zero1024", 1024, 109);
709 Add("zero/zero32768", 32768, 106);
710 Add("zero/zero16385", 16385, 119);
715 template <class Classes
>
716 TestEntry
& ArchiveTestCase
<Classes
>::Add(const char *name
,
722 TestEntry
*& entry
= m_testEntries
[wxString(name
, *wxConvCurrent
)];
723 wxASSERT(entry
== NULL
);
724 entry
= new TestEntry(m_timeStamp
, len
, data
);
725 m_timeStamp
+= wxTimeSpan(0, 1, 30);
729 template <class Classes
>
730 TestEntry
& ArchiveTestCase
<Classes
>::Add(const char *name
,
734 wxCharBuffer
buf(len
);
735 for (int i
= 0; i
< len
; i
++)
736 buf
.data()[i
] = (char)(value
== EOF
? rand() : value
);
737 return Add(name
, buf
, len
);
740 // Create an archive using the wx archive classes, write it to 'out'
742 template <class Classes
>
743 void ArchiveTestCase
<Classes
>::CreateArchive(wxOutputStream
& out
)
745 auto_ptr
<OutputStreamT
> arc(m_factory
->NewStream(out
));
746 TestEntries::iterator it
;
748 OnCreateArchive(*arc
);
750 // We want to try creating entries in various different ways, 'choices'
751 // is just a number used to select between all the various possibilities.
754 for (it
= m_testEntries
.begin(); it
!= m_testEntries
.end(); ++it
) {
756 TestEntry
& testEntry
= *it
->second
;
757 wxString name
= it
->first
;
759 // It should be possible to create a directory entry just by supplying
760 // a name that looks like a directory, or alternatively any old name
761 // can be identified as a directory using SetIsDir or PutNextDirEntry
762 bool setIsDir
= name
.Last() == _T('/') && (choices
& 1);
764 name
.erase(name
.length() - 1);
766 // provide some context for the error message so that we know which
767 // iteration of the loop we were on
768 string
error_entry((_T(" '") + name
+ _T("'")).mb_str());
769 string
error_context(" failed for entry" + error_entry
);
771 if ((choices
& 2) || testEntry
.IsText()) {
772 // try PutNextEntry(EntryT *pEntry)
773 auto_ptr
<EntryT
> entry(m_factory
->NewEntry());
774 entry
->SetName(name
, wxPATH_UNIX
);
777 entry
->SetDateTime(testEntry
.GetDateTime());
778 entry
->SetSize(testEntry
.GetLength());
779 OnCreateEntry(*arc
, testEntry
, entry
.get());
780 CPPUNIT_ASSERT_MESSAGE("PutNextEntry" + error_context
,
781 arc
->PutNextEntry(entry
.release()));
784 // try the convenience methods
785 OnCreateEntry(*arc
, testEntry
);
787 CPPUNIT_ASSERT_MESSAGE("PutNextDirEntry" + error_context
,
788 arc
->PutNextDirEntry(name
, testEntry
.GetDateTime()));
790 CPPUNIT_ASSERT_MESSAGE("PutNextEntry" + error_context
,
791 arc
->PutNextEntry(name
, testEntry
.GetDateTime(),
792 testEntry
.GetLength()));
795 if (name
.Last() != _T('/')) {
796 // for non-dirs write the data
797 arc
->Write(testEntry
.GetData(), testEntry
.GetSize());
798 CPPUNIT_ASSERT_MESSAGE("LastWrite check" + error_context
,
799 arc
->LastWrite() == testEntry
.GetSize());
800 // should work with or without explicit CloseEntry
802 CPPUNIT_ASSERT_MESSAGE("CloseEntry" + error_context
,
806 CPPUNIT_ASSERT_MESSAGE("IsOk" + error_context
, arc
->IsOk());
809 // should work with or without explicit Close
811 CPPUNIT_ASSERT(arc
->Close());
814 // Create an archive using an external archive program
816 template <class Classes
>
817 void ArchiveTestCase
<Classes
>::CreateArchive(wxOutputStream
& out
,
818 const wxString
& archiver
)
820 // for an external archiver the test data need to be written to
825 TestEntries::iterator i
;
826 for (i
= m_testEntries
.begin(); i
!= m_testEntries
.end(); ++i
) {
827 wxFileName
fn(i
->first
, wxPATH_UNIX
);
828 TestEntry
& entry
= *i
->second
;
831 fn
.Mkdir(0777, wxPATH_MKDIR_FULL
);
833 wxFileName::Mkdir(fn
.GetPath(), 0777, wxPATH_MKDIR_FULL
);
834 wxFFileOutputStream
fileout(fn
.GetFullPath());
835 fileout
.Write(entry
.GetData(), entry
.GetSize());
839 for (i
= m_testEntries
.begin(); i
!= m_testEntries
.end(); ++i
) {
840 wxFileName
fn(i
->first
, wxPATH_UNIX
);
841 TestEntry
& entry
= *i
->second
;
842 wxDateTime dt
= entry
.GetDateTime();
845 entry
.SetDateTime(wxDateTime());
848 fn
.SetTimes(NULL
, &dt
, NULL
);
851 if ((m_options
& PipeOut
) == 0) {
852 wxFileName
fn(tmpdir
.GetName());
853 fn
.SetExt(_T("arc"));
854 wxString tmparc
= fn
.GetFullPath();
856 // call the archiver to create an archive file
857 system(wxString::Format(archiver
, tmparc
.c_str()).mb_str());
859 // then load the archive file
861 wxFFileInputStream
in(tmparc
);
866 wxRemoveFile(tmparc
);
869 // for the non-seekable test, have the archiver output to "-"
870 // and read the archive via a pipe
871 PFileInputStream
in(wxString::Format(archiver
, _T("-")));
877 // Do a standard set of modification on an archive, delete an entry,
878 // rename an entry and add an entry
880 template <class Classes
>
881 void ArchiveTestCase
<Classes
>::ModifyArchive(wxInputStream
& in
,
884 auto_ptr
<InputStreamT
> arcIn(m_factory
->NewStream(in
));
885 auto_ptr
<OutputStreamT
> arcOut(m_factory
->NewStream(out
));
888 const wxString deleteName
= _T("bin/bin1000");
889 const wxString renameFrom
= _T("zero/zero1024");
890 const wxString renameTo
= _T("zero/newname");
891 const wxString newName
= _T("newfile");
892 const char *newData
= "New file added as a test\n";
894 arcOut
->CopyArchiveMetaData(*arcIn
);
896 while ((pEntry
= arcIn
->GetNextEntry()) != NULL
) {
897 auto_ptr
<EntryT
> entry(pEntry
);
898 OnSetNotifier(*entry
);
899 wxString name
= entry
->GetName(wxPATH_UNIX
);
901 // provide some context for the error message so that we know which
902 // iteration of the loop we were on
903 string
error_entry((_T(" '") + name
+ _T("'")).mb_str());
904 string
error_context(" failed for entry" + error_entry
);
906 if (name
== deleteName
) {
907 TestEntries::iterator it
= m_testEntries
.find(name
);
908 CPPUNIT_ASSERT_MESSAGE(
909 "deletion failed (already deleted?) for" + error_entry
,
910 it
!= m_testEntries
.end());
911 TestEntry
*p
= it
->second
;
912 m_testEntries
.erase(it
);
916 if (name
== renameFrom
) {
917 entry
->SetName(renameTo
);
918 TestEntries::iterator it
= m_testEntries
.find(renameFrom
);
919 CPPUNIT_ASSERT_MESSAGE(
920 "rename failed (already renamed?) for" + error_entry
,
921 it
!= m_testEntries
.end());
922 TestEntry
*p
= it
->second
;
923 m_testEntries
.erase(it
);
924 m_testEntries
[renameTo
] = p
;
927 CPPUNIT_ASSERT_MESSAGE("CopyEntry" + error_context
,
928 arcOut
->CopyEntry(entry
.release(), *arcIn
));
932 // check that the deletion and rename were done
933 CPPUNIT_ASSERT(m_testEntries
.count(deleteName
) == 0);
934 CPPUNIT_ASSERT(m_testEntries
.count(renameFrom
) == 0);
935 CPPUNIT_ASSERT(m_testEntries
.count(renameTo
) == 1);
937 // check that the end of the input archive was reached without error
938 CPPUNIT_ASSERT(arcIn
->Eof());
940 // try adding a new entry
941 TestEntry
& testEntry
= Add(newName
.mb_str(), newData
);
942 auto_ptr
<EntryT
> newentry(m_factory
->NewEntry());
943 newentry
->SetName(newName
);
944 newentry
->SetDateTime(testEntry
.GetDateTime());
945 newentry
->SetSize(testEntry
.GetLength());
946 OnCreateEntry(*arcOut
, testEntry
, newentry
.get());
947 OnSetNotifier(*newentry
);
948 CPPUNIT_ASSERT(arcOut
->PutNextEntry(newentry
.release()));
949 CPPUNIT_ASSERT(arcOut
->Write(newData
, strlen(newData
)).IsOk());
951 // should work with or without explicit Close
953 CPPUNIT_ASSERT(arcOut
->Close());
956 // Extract an archive using the wx archive classes
958 template <class Classes
>
959 void ArchiveTestCase
<Classes
>::ExtractArchive(wxInputStream
& in
)
961 typedef Ptr
<EntryT
> EntryPtr
;
962 typedef std::list
<EntryPtr
> Entries
;
963 typedef typename
Entries::iterator EntryIter
;
965 auto_ptr
<InputStreamT
> arc(m_factory
->NewStream(in
));
966 int expectedTotal
= m_testEntries
.size();
970 if ((m_options
& PipeIn
) == 0)
971 OnArchiveExtracted(*arc
, expectedTotal
);
973 while (entry
= EntryPtr(arc
->GetNextEntry()), entry
.get() != NULL
) {
974 wxString name
= entry
->GetName(wxPATH_UNIX
);
976 // provide some context for the error message so that we know which
977 // iteration of the loop we were on
978 string
error_entry((_T(" '") + name
+ _T("'")).mb_str());
979 string
error_context(" failed for entry" + error_entry
);
981 TestEntries::iterator it
= m_testEntries
.find(name
);
982 CPPUNIT_ASSERT_MESSAGE(
983 "archive contains an entry that shouldn't be there" + error_entry
,
984 it
!= m_testEntries
.end());
986 const TestEntry
& testEntry
= *it
->second
;
988 wxDateTime dt
= testEntry
.GetDateTime();
990 CPPUNIT_ASSERT_MESSAGE("timestamp check" + error_context
,
991 dt
== entry
->GetDateTime());
993 // non-seekable entries are allowed to have GetSize == wxInvalidOffset
994 // until the end of the entry's data has been read past
995 CPPUNIT_ASSERT_MESSAGE("entry size check" + error_context
,
996 testEntry
.GetLength() == entry
->GetSize() ||
997 ((m_options
& PipeIn
) != 0 && entry
->GetSize() == wxInvalidOffset
));
998 CPPUNIT_ASSERT_MESSAGE(
999 "arc->GetLength() == entry->GetSize()" + error_context
,
1000 arc
->GetLength() == entry
->GetSize());
1002 if (name
.Last() != _T('/'))
1004 CPPUNIT_ASSERT_MESSAGE("!IsDir" + error_context
,
1006 wxCharBuffer
buf(testEntry
.GetSize() + 1);
1007 CPPUNIT_ASSERT_MESSAGE("Read until Eof" + error_context
,
1008 arc
->Read(buf
.data(), testEntry
.GetSize() + 1).Eof());
1009 CPPUNIT_ASSERT_MESSAGE("LastRead check" + error_context
,
1010 arc
->LastRead() == testEntry
.GetSize());
1011 CPPUNIT_ASSERT_MESSAGE("data compare" + error_context
,
1012 !memcmp(buf
.data(), testEntry
.GetData(), testEntry
.GetSize()));
1014 CPPUNIT_ASSERT_MESSAGE("IsDir" + error_context
, entry
->IsDir());
1017 // GetSize() must return the right result in all cases after all the
1018 // data has been read
1019 CPPUNIT_ASSERT_MESSAGE("entry size check" + error_context
,
1020 testEntry
.GetLength() == entry
->GetSize());
1021 CPPUNIT_ASSERT_MESSAGE(
1022 "arc->GetLength() == entry->GetSize()" + error_context
,
1023 arc
->GetLength() == entry
->GetSize());
1025 if ((m_options
& PipeIn
) == 0) {
1026 OnEntryExtracted(*entry
, testEntry
, arc
.get());
1028 m_testEntries
.erase(it
);
1030 entries
.push_back(entry
);
1034 // check that the end of the input archive was reached without error
1035 CPPUNIT_ASSERT(arc
->Eof());
1037 // for non-seekable streams these data are only guaranteed to be
1038 // available once the end of the archive has been reached
1039 if (m_options
& PipeIn
) {
1040 for (EntryIter i
= entries
.begin(); i
!= entries
.end(); ++i
) {
1041 wxString name
= (*i
)->GetName(wxPATH_UNIX
);
1042 TestEntries::iterator j
= m_testEntries
.find(name
);
1043 OnEntryExtracted(**i
, *j
->second
);
1045 m_testEntries
.erase(j
);
1047 OnArchiveExtracted(*arc
, expectedTotal
);
1051 // Extract an archive using an external unarchive program
1053 template <class Classes
>
1054 void ArchiveTestCase
<Classes
>::ExtractArchive(wxInputStream
& in
,
1055 const wxString
& unarchiver
)
1057 // for an external unarchiver, unarchive to a tempdir
1060 if ((m_options
& PipeIn
) == 0) {
1061 wxFileName
fn(tmpdir
.GetName());
1062 fn
.SetExt(_T("arc"));
1063 wxString tmparc
= fn
.GetFullPath();
1065 if (m_options
& Stub
)
1066 in
.SeekI(TestOutputStream::STUB_SIZE
* 2);
1068 // write the archive to a temporary file
1070 wxFFileOutputStream
out(tmparc
);
1076 system(wxString::Format(unarchiver
, tmparc
.c_str()).mb_str());
1077 wxRemoveFile(tmparc
);
1080 // for the non-seekable test, have the archiver extract "-" and
1081 // feed it the archive via a pipe
1082 PFileOutputStream
out(wxString::Format(unarchiver
, _T("-")));
1087 wxString dir
= tmpdir
.GetName();
1091 // Verifies the files produced by an external unarchiver are as expected
1093 template <class Classes
>
1094 void ArchiveTestCase
<Classes
>::VerifyDir(wxString
& path
, size_t rootlen
/*=0*/)
1097 path
+= wxFileName::GetPathSeparator();
1098 int pos
= path
.length();
1104 if (dir
.Open(path
) && dir
.GetFirst(&name
)) {
1106 path
.replace(pos
, wxString::npos
, name
);
1107 name
= m_factory
->GetInternalName(
1108 path
.substr(rootlen
, wxString::npos
));
1110 bool isDir
= wxDirExists(path
);
1114 // provide some context for the error message so that we know which
1115 // iteration of the loop we were on
1116 string
error_entry((_T(" '") + name
+ _T("'")).mb_str());
1117 string
error_context(" failed for entry" + error_entry
);
1119 TestEntries::iterator it
= m_testEntries
.find(name
);
1120 CPPUNIT_ASSERT_MESSAGE(
1121 "archive contains an entry that shouldn't be there"
1123 it
!= m_testEntries
.end());
1125 const TestEntry
& testEntry
= *it
->second
;
1128 CPPUNIT_ASSERT_MESSAGE("timestamp check" + error_context
,
1129 testEntry
.GetDateTime() ==
1130 wxFileName(path
).GetModificationTime());
1133 wxFFileInputStream
in(path
);
1134 CPPUNIT_ASSERT_MESSAGE(
1135 "entry not found in archive" + error_entry
, in
.Ok());
1137 size_t size
= (size_t)in
.GetLength();
1138 wxCharBuffer
buf(size
);
1139 CPPUNIT_ASSERT_MESSAGE("Read" + error_context
,
1140 in
.Read(buf
.data(), size
).LastRead() == size
);
1141 CPPUNIT_ASSERT_MESSAGE("size check" + error_context
,
1142 testEntry
.GetSize() == size
);
1143 CPPUNIT_ASSERT_MESSAGE("data compare" + error_context
,
1144 memcmp(buf
.data(), testEntry
.GetData(), size
) == 0);
1147 VerifyDir(path
, rootlen
);
1151 m_testEntries
.erase(it
);
1153 while (dir
.GetNext(&name
));
1157 // test the simple iterators that give away ownership of an entry
1159 template <class Classes
>
1160 void ArchiveTestCase
<Classes
>::TestIterator(wxInputStream
& in
)
1162 typedef std::list
<EntryT
*> ArchiveCatalog
;
1163 typedef typename
ArchiveCatalog::iterator CatalogIter
;
1165 auto_ptr
<InputStreamT
> arc(m_factory
->NewStream(in
));
1168 #ifdef WXARC_MEMBER_TEMPLATES
1169 ArchiveCatalog
cat((IterT
)*arc
, IterT());
1172 for (IterT
i(*arc
); i
!= IterT(); ++i
)
1176 for (CatalogIter it
= cat
.begin(); it
!= cat
.end(); ++it
) {
1177 auto_ptr
<EntryT
> entry(*it
);
1178 count
+= m_testEntries
.count(entry
->GetName(wxPATH_UNIX
));
1181 CPPUNIT_ASSERT(m_testEntries
.size() == cat
.size());
1182 CPPUNIT_ASSERT(count
== cat
.size());
1185 // test the pair iterators that can be used to load a std::map or wxHashMap
1186 // these also give away ownership of entries
1188 template <class Classes
>
1189 void ArchiveTestCase
<Classes
>::TestPairIterator(wxInputStream
& in
)
1191 typedef std::map
<wxString
, EntryT
*> ArchiveCatalog
;
1192 typedef typename
ArchiveCatalog::iterator CatalogIter
;
1194 auto_ptr
<InputStreamT
> arc(m_factory
->NewStream(in
));
1197 #ifdef WXARC_MEMBER_TEMPLATES
1198 ArchiveCatalog
cat((PairIterT
)*arc
, PairIterT());
1201 for (PairIterT
i(*arc
); i
!= PairIterT(); ++i
)
1205 for (CatalogIter it
= cat
.begin(); it
!= cat
.end(); ++it
) {
1206 auto_ptr
<EntryT
> entry(it
->second
);
1207 count
+= m_testEntries
.count(entry
->GetName(wxPATH_UNIX
));
1210 CPPUNIT_ASSERT(m_testEntries
.size() == cat
.size());
1211 CPPUNIT_ASSERT(count
== cat
.size());
1214 // simple iterators using smart pointers, no need to worry about ownership
1216 template <class Classes
>
1217 void ArchiveTestCase
<Classes
>::TestSmartIterator(wxInputStream
& in
)
1219 typedef std::list
<Ptr
<EntryT
> > ArchiveCatalog
;
1220 typedef typename
ArchiveCatalog::iterator CatalogIter
;
1221 typedef wxArchiveIterator
<InputStreamT
, Ptr
<EntryT
> > Iter
;
1223 auto_ptr
<InputStreamT
> arc(m_factory
->NewStream(in
));
1225 #ifdef WXARC_MEMBER_TEMPLATES
1226 ArchiveCatalog
cat((Iter
)*arc
, Iter());
1229 for (Iter
i(*arc
); i
!= Iter(); ++i
)
1233 CPPUNIT_ASSERT(m_testEntries
.size() == cat
.size());
1235 for (CatalogIter it
= cat
.begin(); it
!= cat
.end(); ++it
)
1236 CPPUNIT_ASSERT(m_testEntries
.count((*it
)->GetName(wxPATH_UNIX
)));
1239 // pair iterator using smart pointers
1241 template <class Classes
>
1242 void ArchiveTestCase
<Classes
>::TestSmartPairIterator(wxInputStream
& in
)
1244 #if defined _MSC_VER && defined _MSC_VER < 1200
1245 // With VC++ 5.0 the '=' operator of std::pair breaks when the second
1246 // type is Ptr<EntryT>, so this iterator can't be made to work.
1249 typedef std::map
<wxString
, Ptr
<EntryT
> > ArchiveCatalog
;
1250 typedef typename
ArchiveCatalog::iterator CatalogIter
;
1251 typedef wxArchiveIterator
<InputStreamT
,
1252 std::pair
<wxString
, Ptr
<EntryT
> > > PairIter
;
1254 auto_ptr
<InputStreamT
> arc(m_factory
->NewStream(in
));
1256 #ifdef WXARC_MEMBER_TEMPLATES
1257 ArchiveCatalog
cat((PairIter
)*arc
, PairIter());
1260 for (PairIter
i(*arc
); i
!= PairIter(); ++i
)
1264 CPPUNIT_ASSERT(m_testEntries
.size() == cat
.size());
1266 for (CatalogIter it
= cat
.begin(); it
!= cat
.end(); ++it
)
1267 CPPUNIT_ASSERT(m_testEntries
.count(it
->second
->GetName(wxPATH_UNIX
)));
1271 // try reading two entries at the same time
1273 template <class Classes
>
1274 void ArchiveTestCase
<Classes
>::ReadSimultaneous(TestInputStream
& in
)
1276 typedef std::map
<wxString
, Ptr
<EntryT
> > ArchiveCatalog
;
1277 typedef wxArchiveIterator
<InputStreamT
,
1278 std::pair
<wxString
, Ptr
<EntryT
> > > PairIter
;
1280 // create two archive input streams
1281 TestInputStream
in2(in
);
1282 auto_ptr
<InputStreamT
> arc(m_factory
->NewStream(in
));
1283 auto_ptr
<InputStreamT
> arc2(m_factory
->NewStream(in2
));
1286 #ifdef WXARC_MEMBER_TEMPLATES
1287 ArchiveCatalog
cat((PairIter
)*arc
, PairIter());
1290 for (PairIter
i(*arc
); i
!= PairIter(); ++i
)
1294 // the names of two entries to read
1295 const wxChar
*name
= _T("text/small");
1296 const wxChar
*name2
= _T("bin/bin1000");
1299 typename
ArchiveCatalog::iterator j
;
1300 CPPUNIT_ASSERT((j
= cat
.find(name
)) != cat
.end());
1301 CPPUNIT_ASSERT(arc
->OpenEntry(*j
->second
));
1302 CPPUNIT_ASSERT((j
= cat
.find(name2
)) != cat
.end());
1303 CPPUNIT_ASSERT(arc2
->OpenEntry(*j
->second
));
1305 // get pointers to the expected data
1306 TestEntries::iterator k
;
1307 CPPUNIT_ASSERT((k
= m_testEntries
.find(name
)) != m_testEntries
.end());
1308 TestEntry
*entry
= k
->second
;
1309 CPPUNIT_ASSERT((k
= m_testEntries
.find(name2
)) != m_testEntries
.end());
1310 TestEntry
*entry2
= k
->second
;
1312 size_t count
= 0, count2
= 0;
1313 size_t size
= entry
->GetSize(), size2
= entry2
->GetSize();
1314 const char *data
= entry
->GetData(), *data2
= entry2
->GetData();
1316 // read and check the two entries in parallel, character by character
1317 while (arc
->IsOk() || arc2
->IsOk()) {
1318 char ch
= arc
->GetC();
1319 if (arc
->LastRead() == 1) {
1320 CPPUNIT_ASSERT(count
< size
);
1321 CPPUNIT_ASSERT(ch
== data
[count
++]);
1323 char ch2
= arc2
->GetC();
1324 if (arc2
->LastRead() == 1) {
1325 CPPUNIT_ASSERT(count2
< size2
);
1326 CPPUNIT_ASSERT(ch2
== data2
[count2
++]);
1330 CPPUNIT_ASSERT(arc
->Eof());
1331 CPPUNIT_ASSERT(arc2
->Eof());
1332 CPPUNIT_ASSERT(count
== size
);
1333 CPPUNIT_ASSERT(count2
== size2
);
1336 // Nothing useful can be done with a generic notifier yet, so just test one
1339 template <class NotifierT
, class EntryT
>
1340 class ArchiveNotifier
: public NotifierT
1343 void OnEntryUpdated(EntryT
& WXUNUSED(entry
)) { }
1346 template <class Classes
>
1347 void ArchiveTestCase
<Classes
>::OnSetNotifier(EntryT
& entry
)
1349 static ArchiveNotifier
<NotifierT
, EntryT
> notifier
;
1350 entry
.SetNotifier(notifier
);
1354 ///////////////////////////////////////////////////////////////////////////////
1355 // ArchiveTestCase<ZipClasses> could be used directly, but instead this
1356 // derived class is used so that zip specific features can be tested.
1358 class ZipTestCase
: public ArchiveTestCase
<ZipClasses
>
1361 ZipTestCase(string name
,
1364 const wxString
& archiver
= wxEmptyString
,
1365 const wxString
& unarchiver
= wxEmptyString
)
1367 ArchiveTestCase
<ZipClasses
>(name
, id
, new wxZipClassFactory
,
1368 options
, archiver
, unarchiver
),
1373 void OnCreateArchive(wxZipOutputStream
& zip
);
1375 void OnArchiveExtracted(wxZipInputStream
& zip
, int expectedTotal
);
1377 void OnCreateEntry(wxZipOutputStream
& zip
,
1378 TestEntry
& testEntry
,
1381 void OnEntryExtracted(wxZipEntry
& entry
,
1382 const TestEntry
& testEntry
,
1383 wxZipInputStream
*arc
);
1385 void OnSetNotifier(EntryT
& entry
);
1391 void ZipTestCase::OnCreateArchive(wxZipOutputStream
& zip
)
1393 m_comment
<< _T("Comment for test ") << m_id
;
1394 zip
.SetComment(m_comment
);
1397 void ZipTestCase::OnArchiveExtracted(wxZipInputStream
& zip
, int expectedTotal
)
1399 CPPUNIT_ASSERT(zip
.GetComment() == m_comment
);
1400 CPPUNIT_ASSERT(zip
.GetTotalEntries() == expectedTotal
);
1403 void ZipTestCase::OnCreateEntry(wxZipOutputStream
& zip
,
1404 TestEntry
& testEntry
,
1407 zip
.SetLevel((m_id
+ m_count
) % 10);
1410 switch ((m_id
+ m_count
) % 5) {
1413 wxString comment
= _T("Comment for ") + entry
->GetName();
1414 entry
->SetComment(comment
);
1415 // lowercase the expected result, and the notifier should do
1416 // the same for the zip entries when ModifyArchive() runs
1417 testEntry
.SetComment(comment
.Lower());
1421 entry
->SetMethod(wxZIP_METHOD_STORE
);
1424 entry
->SetMethod(wxZIP_METHOD_DEFLATE
);
1427 entry
->SetIsText(testEntry
.IsText());
1433 void ZipTestCase::OnEntryExtracted(wxZipEntry
& entry
,
1434 const TestEntry
& testEntry
,
1435 wxZipInputStream
*arc
)
1437 // provide some context for the error message so that we know which
1438 // iteration of the loop we were on
1439 wxString name
= _T(" '") + entry
.GetName() + _T("'");
1440 string
error_entry(name
.mb_str());
1441 string
error_context(" failed for entry" + error_entry
);
1443 CPPUNIT_ASSERT_MESSAGE("GetComment" + error_context
,
1444 entry
.GetComment() == testEntry
.GetComment());
1446 // for seekable streams, GetNextEntry() doesn't read the local header so
1447 // call OpenEntry() to do it
1448 if (arc
&& (m_options
& PipeIn
) == 0 && entry
.IsDir())
1449 arc
->OpenEntry(entry
);
1451 CPPUNIT_ASSERT_MESSAGE("IsText" + error_context
,
1452 entry
.IsText() == testEntry
.IsText());
1454 CPPUNIT_ASSERT_MESSAGE("Extra/LocalExtra mismatch for entry" + error_entry
,
1455 (entry
.GetExtraLen() != 0 && entry
.GetLocalExtraLen() != 0) ||
1456 (entry
.GetExtraLen() == 0 && entry
.GetLocalExtraLen() == 0));
1459 // check the notifier mechanism by using it to fold the entry comments to
1462 class ZipNotifier
: public wxZipNotifier
1465 void OnEntryUpdated(wxZipEntry
& entry
);
1468 void ZipNotifier::OnEntryUpdated(wxZipEntry
& entry
)
1470 entry
.SetComment(entry
.GetComment().Lower());
1473 void ZipTestCase::OnSetNotifier(EntryT
& entry
)
1475 static ZipNotifier notifier
;
1476 entry
.SetNotifier(notifier
);
1480 ///////////////////////////////////////////////////////////////////////////////
1481 // 'zip - -' produces local headers without the size field set. This is a
1482 // case not covered by all the other tests, so this class tests it as a
1485 class ZipPipeTestCase
: public CppUnit::TestCase
1488 ZipPipeTestCase(string name
, int options
) :
1489 CppUnit::TestCase(name
), m_options(options
) { }
1496 void ZipPipeTestCase::runTest()
1498 TestOutputStream
out(m_options
);
1500 wxString testdata
= _T("test data to pipe through zip");
1501 wxString cmd
= _T("echo ") + testdata
+ _T(" | zip -q - -");
1504 PFileInputStream
in(cmd
);
1509 TestInputStream
in(out
);
1510 wxZipInputStream
zip(in
);
1512 auto_ptr
<wxZipEntry
> entry(zip
.GetNextEntry());
1513 CPPUNIT_ASSERT(entry
.get() != NULL
);
1515 if ((m_options
& PipeIn
) == 0)
1516 CPPUNIT_ASSERT(entry
->GetSize() != wxInvalidOffset
);
1519 size_t len
= zip
.Read(buf
, sizeof(buf
) - 1).LastRead();
1521 while (len
> 0 && buf
[len
- 1] <= 32)
1525 CPPUNIT_ASSERT(zip
.Eof());
1526 CPPUNIT_ASSERT(wxString(buf
, *wxConvCurrent
) == testdata
);
1530 ///////////////////////////////////////////////////////////////////////////////
1533 class ArchiveTestSuite
: public CppUnit::TestSuite
1537 static CppUnit::Test
*suite()
1538 { return (new ArchiveTestSuite
)->makeSuite(); }
1544 ArchiveTestSuite
*makeSuite();
1545 void AddCmd(wxArrayString
& cmdlist
, const wxString
& cmd
);
1546 bool IsInPath(const wxString
& cmd
);
1548 string
Description(const wxString
& type
,
1550 bool genericInterface
= false,
1551 const wxString
& archiver
= wxEmptyString
,
1552 const wxString
& unarchiver
= wxEmptyString
);
1555 ArchiveTestSuite::ArchiveTestSuite()
1556 : CppUnit::TestSuite("ArchiveTestSuite"),
1559 m_path
.AddEnvList(_T("PATH"));
1562 // add the command for an external archiver to the list, testing for it in
1565 void ArchiveTestSuite::AddCmd(wxArrayString
& cmdlist
, const wxString
& cmd
)
1567 if (cmdlist
.empty())
1568 cmdlist
.push_back(_T(""));
1570 cmdlist
.push_back(cmd
);
1573 bool ArchiveTestSuite::IsInPath(const wxString
& cmd
)
1575 wxString c
= cmd
.BeforeFirst(_T(' '));
1579 return !m_path
.FindValidPath(c
).empty();
1582 // make the test suite
1584 ArchiveTestSuite
*ArchiveTestSuite::makeSuite()
1586 typedef wxArrayString::iterator Iter
;
1587 wxArrayString zippers
;
1588 wxArrayString unzippers
;
1590 AddCmd(zippers
, _T("zip -qr %s *"));
1591 AddCmd(unzippers
, _T("unzip -q %s"));
1593 for (int genInterface
= 0; genInterface
< 2; genInterface
++)
1594 for (Iter i
= unzippers
.begin(); i
!= unzippers
.end(); ++i
)
1595 for (Iter j
= zippers
.begin(); j
!= zippers
.end(); ++j
)
1596 for (int options
= 0; options
<= AllOptions
; options
++)
1598 // unzip doesn't support piping in the zip
1599 if ((options
& PipeIn
) && !i
->empty())
1601 #ifdef WXARC_NO_POPEN
1602 // if no popen then can use piped output of zip
1603 if ((options
& PipeOut
) && !j
->empty())
1606 string name
= Description(_T("wxZip"), options
,
1607 genInterface
!= 0, *j
, *i
);
1610 addTest(new ArchiveTestCase
<ArchiveClasses
>(
1612 new wxZipClassFactory
,
1615 addTest(new ZipTestCase(name
, m_id
, options
, *j
, *i
));
1620 #ifndef WXARC_NO_POPEN
1621 // if have popen then can check the piped output of 'zip - -'
1622 if (IsInPath(_T("zip")))
1623 for (int options
= 0; options
<= PipeIn
; options
+= PipeIn
) {
1624 string name
= Description(_T("ZipPipeTestCase"), options
);
1625 addTest(new ZipPipeTestCase(name
, options
));
1633 // make a display string for the option bits
1635 string
ArchiveTestSuite::Description(const wxString
& type
,
1637 bool genericInterface
,
1638 const wxString
& archiver
,
1639 const wxString
& unarchiver
)
1642 descr
<< m_id
<< _T(" ");
1644 if (genericInterface
)
1645 descr
<< _T("wxArchive (") << type
<< _T(")");
1649 if (!archiver
.empty())
1650 descr
<< _T(" ") << archiver
.BeforeFirst(_T(' '));
1651 if (!unarchiver
.empty())
1652 descr
<< _T(" ") << unarchiver
.BeforeFirst(_T(' '));
1656 if ((options
& PipeIn
) != 0)
1657 optstr
+= _T("|PipeIn");
1658 if ((options
& PipeOut
) != 0)
1659 optstr
+= _T("|PipeOut");
1660 if ((options
& Stub
) != 0)
1661 optstr
+= _T("|Stub");
1662 if (!optstr
.empty())
1663 optstr
= _T(" (") + optstr
.substr(1) + _T(")");
1667 return (const char*)descr
.mb_str();
1670 // register in the unnamed registry so that these tests are run by default
1671 CPPUNIT_TEST_SUITE_REGISTRATION(ArchiveTestSuite
);
1673 // also include in it's own registry so that these tests can be run alone
1674 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(ArchiveTestSuite
, "ArchiveTestSuite");
1676 #endif // wxUSE_STREAMS