]> git.saurik.com Git - wxWidgets.git/blobdiff - tests/archive/archivetest.cpp
made wxLogGui more flexible and documented it and added example of customizing it...
[wxWidgets.git] / tests / archive / archivetest.cpp
index e836c3a16eb433e4e7d1c3dc539b63c835e594d4..dc5caa473eb9ecce2d1a941336cc73fc453004c1 100644 (file)
@@ -7,7 +7,7 @@
 // Licence:     wxWindows licence
 ///////////////////////////////////////////////////////////////////////////////
 
-#include "wx/wxprec.h"
+#include "testprec.h"
 
 #ifdef __BORLANDC__
 #   pragma hdrstop
 #   include "wx/wx.h"
 #endif
 
-#if wxUSE_STREAMS
+#if wxUSE_STREAMS && wxUSE_ARCHIVE_STREAMS
 
-#define WX_TEST_ARCHIVE_ITERATOR
+// VC++ 6 warns that the list iterator's '->' operator will not work whenever
+// std::list is used with a non-pointer, so switch it off.
+#if defined _MSC_VER && _MSC_VER < 1300
+#pragma warning (disable:4284)
+#endif
 
-#include "wx/zipstrm.h"
-#include "wx/mstream.h"
-#include "wx/wfstream.h"
+#include "archivetest.h"
 #include "wx/dir.h"
-#include "wx/cppunit.h"
 #include <string>
 #include <list>
+#include <map>
 #include <sys/stat.h>
 
+using std::string;
+using std::auto_ptr;
+
+
 // Check whether member templates can be used
 //
 #if defined __GNUC__ && \
     (__GNUC__ >= 3 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95))
 #   define WXARC_MEMBER_TEMPLATES
 #endif
-#if defined _MSC_VER && _MSC_VER >= 1310
+#if defined _MSC_VER && _MSC_VER >= 1310 && !defined __WIN64__
 #   define WXARC_MEMBER_TEMPLATES
 #endif
 #if defined __BORLANDC__ && __BORLANDC__ >= 0x530
 #endif
 
 
-///////////////////////////////////////////////////////////////////////////////
-// Bit flags for options for the tests
-
-enum Options
-{
-    PipeIn      = 0x01,     // input streams are non-seekable
-    PipeOut     = 0x02,     // output streams are non-seekable
-    Stub        = 0x04,     // the archive should be appended to a stub
-    AllOptions  = 0x07
-};
-
-
-///////////////////////////////////////////////////////////////////////////////
-// These structs are passed as the template parameter of the test case to
-// specify a set of classes to use in the test. This allows either the generic
-// wxArchiveXXX interface to be exercised or the specific interface for a
-// particular archive format e.g. wxZipXXX.
-
-struct ArchiveClasses
-{
-    typedef wxArchiveEntry EntryT;
-    typedef wxArchiveInputStream InputStreamT;
-    typedef wxArchiveOutputStream OutputStreamT;
-    typedef wxArchiveClassFactory ClassFactoryT;
-    typedef wxArchiveNotifier NotifierT;
-    typedef wxArchiveIter IterT;
-    typedef wxArchivePairIter PairIterT;
-};
-
-struct ZipClasses
-{
-    typedef wxZipEntry EntryT;
-    typedef wxZipInputStream InputStreamT;
-    typedef wxZipOutputStream OutputStreamT;
-    typedef wxZipClassFactory ClassFactoryT;
-    typedef wxZipNotifier NotifierT;
-    typedef wxZipIter IterT;
-    typedef wxZipPairIter PairIterT;
-};
-
-
 ///////////////////////////////////////////////////////////////////////////////
 // A class to hold a test entry
 
-class TestEntry
-{
-public:
-    TestEntry(const wxDateTime& dt, int len, const char *data);
-    ~TestEntry() { delete [] m_data; }
-
-    wxDateTime GetDateTime() const  { return m_dt; }
-    wxFileOffset GetLength() const  { return m_len; }
-    size_t GetSize() const          { return m_len; }
-    const char *GetData() const     { return m_data; }
-    wxString GetComment() const     { return m_comment; }
-    bool IsText() const             { return m_isText; }
-
-    void SetComment(const wxString& comment) { m_comment = comment; }
-    void SetDateTime(const wxDateTime& dt)   { m_dt = dt; }
-
-private:
-    wxDateTime m_dt;
-    size_t m_len;
-    const char *m_data;
-    wxString m_comment;
-    bool m_isText;
-};
-
 TestEntry::TestEntry(const wxDateTime& dt, int len, const char *data)
   : m_dt(dt),
     m_len(len),
     m_isText(len > 0)
 {
-    char *d = new char[len];
-    memcpy(d, data, len);
-    m_data = d;
+    m_data = new char[len];
+    memcpy(m_data, data, len);
 
     for (int i = 0; i < len && m_isText; i++)
         m_isText = (signed char)m_data[i] > 0;
@@ -142,34 +82,9 @@ TestEntry::TestEntry(const wxDateTime& dt, int len, const char *data)
 // TestOutputStream and TestInputStream are memory streams which can be
 // seekable or non-seekable.
 
-class TestOutputStream : public wxOutputStream
-{
-public:
-    TestOutputStream(int options);
-
-    ~TestOutputStream() { delete [] m_data; }
-
-    int GetOptions() const { return m_options; }
-    size_t GetSize() const { return m_size; }
-
-    // gives away the data, this stream is then empty, and can be reused
-    void GetData(const char*& data, size_t& size);
-
-    enum { STUB_SIZE = 2048, INITIAL_SIZE = 0x18000, SEEK_LIMIT = 0x100000 };
-
-private:
-    void Init();
-
-    wxFileOffset OnSysSeek(wxFileOffset pos, wxSeekMode mode);
-    wxFileOffset OnSysTell() const;
-    size_t OnSysWrite(const void *buffer, size_t size);
-
-    int m_options;
-    size_t m_pos;
-    size_t m_capacity;
-    size_t m_size;
-    char *m_data;
-};
+const size_t STUB_SIZE = 2048;
+const size_t INITIAL_SIZE = 0x18000;
+const wxFileOffset SEEK_LIMIT = 0x100000;
 
 TestOutputStream::TestOutputStream(int options)
   : m_options(options)
@@ -201,7 +116,7 @@ wxFileOffset TestOutputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode)
         }
         if (pos < 0 || pos > SEEK_LIMIT)
             return wxInvalidOffset;
-        m_pos = pos;
+        m_pos = (size_t)pos;
         return m_pos;
     }
     return wxInvalidOffset;
@@ -209,7 +124,7 @@ wxFileOffset TestOutputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode)
 
 wxFileOffset TestOutputStream::OnSysTell() const
 {
-    return (m_options & PipeOut) == 0 ? m_pos : wxInvalidOffset;
+    return (m_options & PipeOut) == 0 ? (wxFileOffset)m_pos : wxInvalidOffset;
 }
 
 size_t TestOutputStream::OnSysWrite(const void *buffer, size_t size)
@@ -246,7 +161,7 @@ size_t TestOutputStream::OnSysWrite(const void *buffer, size_t size)
     return size;
 }
 
-void TestOutputStream::GetData(const char*& data, size_t& size)
+void TestOutputStream::GetData(char*& data, size_t& size)
 {
     data = m_data;
     size = m_size;
@@ -272,44 +187,26 @@ void TestOutputStream::GetData(const char*& data, size_t& size)
     Reset();
 }
 
-class TestInputStream : public wxInputStream
-{
-public:
-    // ctor takes the data from the output stream, which is then empty
-    TestInputStream(TestOutputStream& out) : m_data(NULL) { SetData(out); }
-    // this ctor 'dups'
-    TestInputStream(const TestInputStream& in);
-    ~TestInputStream() { delete [] m_data; }
 
-    void Rewind();
-    size_t GetSize() const { return m_size; }
-    void SetData(TestOutputStream& out);
-
-private:
-    wxFileOffset OnSysSeek(wxFileOffset pos, wxSeekMode mode);
-    wxFileOffset OnSysTell() const;
-    size_t OnSysRead(void *buffer, size_t size);
-
-    int m_options;
-    size_t m_pos;
-    size_t m_size;
-    const char *m_data;
-};
+///////////////////////////////////////////////////////////////////////////////
+// TestOutputStream and TestInputStream are memory streams which can be
+// seekable or non-seekable.
 
 TestInputStream::TestInputStream(const TestInputStream& in)
-  : m_options(in.m_options),
+  : wxInputStream(),
+    m_options(in.m_options),
     m_pos(in.m_pos),
-    m_size(in.m_size)
+    m_size(in.m_size),
+    m_eoftype(in.m_eoftype)
 {
-    char *p = new char[m_size];
-    memcpy(p, in.m_data, m_size);
-    m_data = p;
+    m_data = new char[m_size];
+    memcpy(m_data, in.m_data, m_size);
 }
 
 void TestInputStream::Rewind()
 {
     if ((m_options & Stub) && (m_options & PipeIn))
-        m_pos = TestOutputStream::STUB_SIZE * 2;
+        m_pos = STUB_SIZE * 2;
     else
         m_pos = 0;
 
@@ -319,6 +216,8 @@ void TestInputStream::Rewind()
         m_wbacksize = 0;
         m_wbackcur = 0;
     }
+
+    Reset();
 }
 
 void TestInputStream::SetData(TestOutputStream& out)
@@ -327,7 +226,6 @@ void TestInputStream::SetData(TestOutputStream& out)
     m_options = out.GetOptions();
     out.GetData(m_data, m_size);
     Rewind();
-    Reset();
 }
 
 wxFileOffset TestInputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode)
@@ -338,9 +236,9 @@ wxFileOffset TestInputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode)
             case wxFromCurrent: pos += m_pos; break;
             case wxFromEnd:     pos += m_size; break;
         }
-        if (pos < 0 || pos > TestOutputStream::SEEK_LIMIT)
+        if (pos < 0 || pos > SEEK_LIMIT)
             return wxInvalidOffset;
-        m_pos = pos;
+        m_pos = (size_t)pos;
         return m_pos;
     }
     return wxInvalidOffset;
@@ -348,23 +246,35 @@ wxFileOffset TestInputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode)
 
 wxFileOffset TestInputStream::OnSysTell() const
 {
-    return (m_options & PipeIn) == 0 ? m_pos : wxInvalidOffset;
+    return (m_options & PipeIn) == 0 ? (wxFileOffset)m_pos : wxInvalidOffset;
 }
 
 size_t TestInputStream::OnSysRead(void *buffer, size_t size)
 {
     if (!IsOk() || !size)
         return 0;
-    if (m_size <= m_pos) {
-        m_lasterror = wxSTREAM_EOF;
-        return 0;
+
+    size_t count;
+
+    if (m_pos >= m_size)
+        count = 0;
+    else if (m_size - m_pos < size)
+        count = m_size - m_pos;
+    else
+        count = size;
+
+    if (count) {
+        memcpy(buffer, m_data + m_pos, count);
+        m_pos += count;
     }
 
-    if (m_size - m_pos < size)
-        size = m_size - m_pos;
-    memcpy(buffer, m_data + m_pos, size);
-    m_pos += size;
-    return size;
+    if (((m_eoftype & AtLast) != 0 && m_pos >= m_size) || count < size)
+        if ((m_eoftype & WithError) != 0)
+            m_lasterror = wxSTREAM_READ_ERROR;
+        else
+            m_lasterror = wxSTREAM_EOF;
+
+    return count;
 }
 
 
@@ -424,7 +334,7 @@ private:
 TempDir::TempDir()
 {
     wxString tmp = wxFileName::CreateTempFileName(_T("arctest-"));
-    if (tmp != wxEmptyString) {
+    if (!tmp.empty()) {
         wxRemoveFile(tmp);
         m_original = wxGetCwd();
         CPPUNIT_ASSERT(wxMkdir(tmp, 0700));
@@ -435,7 +345,7 @@ TempDir::TempDir()
 
 TempDir::~TempDir()
 {
-    if (m_tmp != wxEmptyString) {
+    if (!m_tmp.empty()) {
         wxSetWorkingDirectory(m_original);
         RemoveDir(m_tmp);
     }
@@ -501,132 +411,59 @@ void TempDir::RemoveDir(wxString& path)
 #   define WXARC_b
 #endif
 
-class PFileInputStream : public wxFFileInputStream
+PFileInputStream::PFileInputStream(const wxString& cmd)
+  : wxFFileInputStream(WXARC_popen(cmd.mb_str(), "r" WXARC_b))
 {
-public:
-    PFileInputStream(const wxString& cmd) :
-        wxFFileInputStream(WXARC_popen(cmd.mb_str(), "r" WXARC_b)) { }
-    ~PFileInputStream()
-        { WXARC_pclose(m_file->fp()); m_file->Detach(); }
-};
+}
 
-class PFileOutputStream : public wxFFileOutputStream
+PFileInputStream::~PFileInputStream()
 {
-public:
-    PFileOutputStream(const wxString& cmd) :
-        wxFFileOutputStream(WXARC_popen(cmd.mb_str(), "w" WXARC_b)) { }
-    ~PFileOutputStream()
-        { WXARC_pclose(m_file->fp()); m_file->Detach(); }
-};
-
-
-///////////////////////////////////////////////////////////////////////////////
-// The test case
+    WXARC_pclose(m_file->fp()); m_file->Detach();
+}
 
-template <class Classes>
-class ArchiveTestCase : public CppUnit::TestCase
+PFileOutputStream::PFileOutputStream(const wxString& cmd)
+: wxFFileOutputStream(WXARC_popen(cmd.mb_str(), "w" WXARC_b))
 {
-public:
-    ArchiveTestCase(const wxString& name,
-                    int id,
-                    typename Classes::ClassFactoryT *factory,
-                    int options,
-                    const wxString& archiver = wxEmptyString,
-                    const wxString& unarchiver = wxEmptyString);
-
-    ~ArchiveTestCase();
-
-protected:
-    // the classes to test
-    typedef typename Classes::EntryT EntryT;
-    typedef typename Classes::InputStreamT InputStreamT;
-    typedef typename Classes::OutputStreamT OutputStreamT;
-    typedef typename Classes::ClassFactoryT ClassFactoryT;
-    typedef typename Classes::NotifierT NotifierT;
-    typedef typename Classes::IterT IterT;
-    typedef typename Classes::PairIterT PairIterT;
-
-    // the entry point for the test
-    void runTest();
-
-    // create the test data
-    void CreateTestData();
-    TestEntry& Add(const char *name, const char *data, int len = -1);
-    TestEntry& Add(const char *name, int len = 0, int value = EOF);
+}
 
-    // 'archive up' the test data
-    void CreateArchive(wxOutputStream& out);
-    void CreateArchive(wxOutputStream& out, const wxString& archiver);
+PFileOutputStream::~PFileOutputStream()
+{
+    WXARC_pclose(m_file->fp()); m_file->Detach();
+}
 
-    // perform various modifications on the archive
-    void ModifyArchive(wxInputStream& in, wxOutputStream& out);
 
-    // extract the archive and verify its contents
-    void ExtractArchive(wxInputStream& in);
-    void ExtractArchive(wxInputStream& in, const wxString& unarchiver);
-    void VerifyDir(wxString& path, size_t rootlen = 0);
-
-    // tests for the iterators
-    void TestIterator(wxInputStream& in);
-    void TestPairIterator(wxInputStream& in);
-    void TestSmartIterator(wxInputStream& in);
-    void TestSmartPairIterator(wxInputStream& in);
-
-    // try reading two entries at the same time
-    void ReadSimultaneous(TestInputStream& in);
-
-    // overridables
-    virtual void OnCreateArchive(OutputStreamT& WXUNUSED(arc)) { }
-    virtual void OnSetNotifier(EntryT& entry);
-
-    virtual void OnArchiveExtracted(InputStreamT& WXUNUSED(arc),
-                                    int WXUNUSED(expectedTotal)) { }
-
-    virtual void OnCreateEntry(     OutputStreamT& WXUNUSED(arc),
-                                    TestEntry& WXUNUSED(testEntry),
-                                    EntryT *entry = NULL) { (void)entry; }
-
-    virtual void OnEntryExtracted(  EntryT& WXUNUSED(entry),
-                                    const TestEntry& WXUNUSED(testEntry),
-                                    InputStreamT *arc = NULL) { (void)arc; }
-
-    typedef std::map<wxString, TestEntry*> TestEntries;
-    TestEntries m_testEntries;              // test data
-    std::auto_ptr<ClassFactoryT> m_factory; // factory to make classes
-    int m_options;                          // test options
-    wxDateTime m_timeStamp;                 // timestamp to give test entries
-    int m_id;                               // select between the possibilites
-    wxString m_archiver;                    // external archiver
-    wxString m_unarchiver;                  // external unarchiver
-};
+///////////////////////////////////////////////////////////////////////////////
+// The test case
 
-template <class Classes>
-ArchiveTestCase<Classes>::ArchiveTestCase(const wxString& name,
-                                          int id,
-                                          ClassFactoryT *factory,
-                                          int options,
-                                          const wxString& archiver,
-                                          const wxString& unarchiver)
-  : CppUnit::TestCase(std::string(name.mb_str())),
+template <class ClassFactoryT>
+ArchiveTestCase<ClassFactoryT>::ArchiveTestCase(
+    string name,
+    ClassFactoryT *factory,
+    int options,
+    const wxString& archiver,
+    const wxString& unarchiver)
+  :
+    CppUnit::TestCase(TestId::MakeId() + name),
     m_factory(factory),
     m_options(options),
-    m_timeStamp(1, wxDateTime::Mar, 2005, 12, 0),
-    m_id(id),
+    m_timeStamp(1, wxDateTime::Mar, 2004, 12, 0),
+    m_id(TestId::GetId()),
     m_archiver(archiver),
     m_unarchiver(unarchiver)
 {
+    wxASSERT(m_factory.get() != NULL);
 }
 
-template <class Classes>
-ArchiveTestCase<Classes>::~ArchiveTestCase()
+template <class ClassFactoryT>
+ArchiveTestCase<ClassFactoryT>::~ArchiveTestCase()
 {
     TestEntries::iterator it;
     for (it = m_testEntries.begin(); it != m_testEntries.end(); ++it)
         delete it->second;
 }
 
-template <class Classes>
-void ArchiveTestCase<Classes>::runTest()
+template <class ClassFactoryT>
+void ArchiveTestCase<ClassFactoryT>::runTest()
 {
     TestOutputStream out(m_options);
 
@@ -638,9 +475,9 @@ void ArchiveTestCase<Classes>::runTest()
         CreateArchive(out, m_archiver);
 
     // check archive could be created
-    CPPUNIT_ASSERT(out.GetSize() > 0);
+    CPPUNIT_ASSERT(out.GetLength() > 0);
 
-    TestInputStream in(out);
+    TestInputStream in(out, m_id % ((m_options & PipeIn) ? 4 : 3));
 
     TestIterator(in);
     in.Rewind();
@@ -663,13 +500,13 @@ void ArchiveTestCase<Classes>::runTest()
         ExtractArchive(in);
     else
         ExtractArchive(in, m_unarchiver);
-    
+
     // check that all the test entries were found in the archive
     CPPUNIT_ASSERT(m_testEntries.empty());
 }
 
-template <class Classes>
-void ArchiveTestCase<Classes>::CreateTestData()
+template <class ClassFactoryT>
+void ArchiveTestCase<ClassFactoryT>::CreateTestData()
 {
     Add("text/");
     Add("text/empty", "");
@@ -692,10 +529,10 @@ void ArchiveTestCase<Classes>::CreateTestData()
     Add("empty/");
 }
 
-template <class Classes>
-TestEntry& ArchiveTestCase<Classes>::Add(const char *name,
-                                         const char *data,
-                                         int len /*=-1*/)
+template <class ClassFactoryT>
+TestEntry& ArchiveTestCase<ClassFactoryT>::Add(const char *name,
+                                               const char *data,
+                                               int len /*=-1*/)
 {
     if (len == -1)
         len = strlen(data);
@@ -706,23 +543,23 @@ TestEntry& ArchiveTestCase<Classes>::Add(const char *name,
     return *entry;
 }
 
-template <class Classes>
-TestEntry& ArchiveTestCase<Classes>::Add(const char *name,
-                                         int len /*=0*/,
-                                         int value /*=EOF*/)
+template <class ClassFactoryT>
+TestEntry& ArchiveTestCase<ClassFactoryT>::Add(const char *name,
+                                               int len /*=0*/,
+                                               int value /*=EOF*/)
 {
     wxCharBuffer buf(len);
     for (int i = 0; i < len; i++)
-        buf.data()[i] = value == EOF ? rand() : value;
+        buf.data()[i] = (char)(value == EOF ? rand() : value);
     return Add(name, buf, len);
 }
 
 // Create an archive using the wx archive classes, write it to 'out'
 //
-template <class Classes>
-void ArchiveTestCase<Classes>::CreateArchive(wxOutputStream& out)
+template <class ClassFactoryT>
+void ArchiveTestCase<ClassFactoryT>::CreateArchive(wxOutputStream& out)
 {
-    std::auto_ptr<OutputStreamT> arc(m_factory->NewStream(out));
+    auto_ptr<OutputStreamT> arc(m_factory->NewStream(out));
     TestEntries::iterator it;
 
     OnCreateArchive(*arc);
@@ -745,12 +582,12 @@ void ArchiveTestCase<Classes>::CreateArchive(wxOutputStream& out)
 
         // provide some context for the error message so that we know which
         // iteration of the loop we were on
-        std::string error_entry((_T(" '") + name + _T("'")).mb_str());
-        std::string error_context(" failed for entry" + error_entry);
+        string error_entry((_T(" '") + name + _T("'")).mb_str());
+        string error_context(" failed for entry" + error_entry);
 
         if ((choices & 2) || testEntry.IsText()) {
             // try PutNextEntry(EntryT *pEntry)
-            std::auto_ptr<EntryT> entry(m_factory->NewEntry());
+            auto_ptr<EntryT> entry(m_factory->NewEntry());
             entry->SetName(name, wxPATH_UNIX);
             if (setIsDir)
                 entry->SetIsDir();
@@ -772,7 +609,7 @@ void ArchiveTestCase<Classes>::CreateArchive(wxOutputStream& out)
                                       testEntry.GetLength()));
         }
 
-        if (name.Last() != _T('/')) {
+        if (it->first.Last() != _T('/')) {
             // for non-dirs write the data
             arc->Write(testEntry.GetData(), testEntry.GetSize());
             CPPUNIT_ASSERT_MESSAGE("LastWrite check" + error_context,
@@ -793,9 +630,9 @@ void ArchiveTestCase<Classes>::CreateArchive(wxOutputStream& out)
 
 // Create an archive using an external archive program
 //
-template <class Classes>
-void ArchiveTestCase<Classes>::CreateArchive(wxOutputStream& out,
-                                             const wxString& archiver)
+template <class ClassFactoryT>
+void ArchiveTestCase<ClassFactoryT>::CreateArchive(wxOutputStream& out,
+                                                   const wxString& archiver)
 {
     // for an external archiver the test data need to be written to
     // temp files
@@ -831,7 +668,7 @@ void ArchiveTestCase<Classes>::CreateArchive(wxOutputStream& out,
     if ((m_options & PipeOut) == 0) {
         wxFileName fn(tmpdir.GetName());
         fn.SetExt(_T("arc"));
-        wxString tmparc = fn.GetFullPath();
+        wxString tmparc = fn.GetPath(wxPATH_GET_SEPARATOR) + fn.GetFullName();
 
         // call the archiver to create an archive file
         system(wxString::Format(archiver, tmparc.c_str()).mb_str());
@@ -857,13 +694,13 @@ void ArchiveTestCase<Classes>::CreateArchive(wxOutputStream& out,
 // Do a standard set of modification on an archive, delete an entry,
 // rename an entry and add an entry
 //
-template <class Classes>
-void ArchiveTestCase<Classes>::ModifyArchive(wxInputStream& in,
-                                             wxOutputStream& out)
+template <class ClassFactoryT>
+void ArchiveTestCase<ClassFactoryT>::ModifyArchive(wxInputStream& in,
+                                                   wxOutputStream& out)
 {
-    std::auto_ptr<InputStreamT> arcIn(m_factory->NewStream(in));
-    std::auto_ptr<OutputStreamT> arcOut(m_factory->NewStream(out));
-    std::auto_ptr<EntryT> entry;
+    auto_ptr<InputStreamT> arcIn(m_factory->NewStream(in));
+    auto_ptr<OutputStreamT> arcOut(m_factory->NewStream(out));
+    EntryT *pEntry;
 
     const wxString deleteName = _T("bin/bin1000");
     const wxString renameFrom = _T("zero/zero1024");
@@ -873,14 +710,15 @@ void ArchiveTestCase<Classes>::ModifyArchive(wxInputStream& in,
 
     arcOut->CopyArchiveMetaData(*arcIn);
 
-    while (entry.reset(arcIn->GetNextEntry()), entry.get() != NULL) {
+    while ((pEntry = arcIn->GetNextEntry()) != NULL) {
+        auto_ptr<EntryT> entry(pEntry);
         OnSetNotifier(*entry);
         wxString name = entry->GetName(wxPATH_UNIX);
 
         // provide some context for the error message so that we know which
         // iteration of the loop we were on
-        std::string error_entry((_T(" '") + name + _T("'")).mb_str());
-        std::string error_context(" failed for entry" + error_entry);
+        string error_entry((_T(" '") + name + _T("'")).mb_str());
+        string error_context(" failed for entry" + error_entry);
 
         if (name == deleteName) {
             TestEntries::iterator it = m_testEntries.find(name);
@@ -918,13 +756,13 @@ void ArchiveTestCase<Classes>::ModifyArchive(wxInputStream& in,
 
     // try adding a new entry
     TestEntry& testEntry = Add(newName.mb_str(), newData);
-    entry.reset(m_factory->NewEntry());
-    entry->SetName(newName);
-    entry->SetDateTime(testEntry.GetDateTime());
-    entry->SetSize(testEntry.GetLength());
-    OnCreateEntry(*arcOut, testEntry, entry.get());
-    OnSetNotifier(*entry);
-    CPPUNIT_ASSERT(arcOut->PutNextEntry(entry.release()));
+    auto_ptr<EntryT> newentry(m_factory->NewEntry());
+    newentry->SetName(newName);
+    newentry->SetDateTime(testEntry.GetDateTime());
+    newentry->SetSize(testEntry.GetLength());
+    OnCreateEntry(*arcOut, testEntry, newentry.get());
+    OnSetNotifier(*newentry);
+    CPPUNIT_ASSERT(arcOut->PutNextEntry(newentry.release()));
     CPPUNIT_ASSERT(arcOut->Write(newData, strlen(newData)).IsOk());
 
     // should work with or without explicit Close
@@ -934,14 +772,14 @@ void ArchiveTestCase<Classes>::ModifyArchive(wxInputStream& in,
 
 // Extract an archive using the wx archive classes
 //
-template <class Classes>
-void ArchiveTestCase<Classes>::ExtractArchive(wxInputStream& in)
+template <class ClassFactoryT>
+void ArchiveTestCase<ClassFactoryT>::ExtractArchive(wxInputStream& in)
 {
     typedef Ptr<EntryT> EntryPtr;
     typedef std::list<EntryPtr> Entries;
     typedef typename Entries::iterator EntryIter;
 
-    std::auto_ptr<InputStreamT> arc(m_factory->NewStream(in));
+    auto_ptr<InputStreamT> arc(m_factory->NewStream(in));
     int expectedTotal = m_testEntries.size();
     EntryPtr entry;
     Entries entries;
@@ -954,8 +792,8 @@ void ArchiveTestCase<Classes>::ExtractArchive(wxInputStream& in)
 
         // provide some context for the error message so that we know which
         // iteration of the loop we were on
-        std::string error_entry((_T(" '") + name + _T("'")).mb_str());
-        std::string error_context(" failed for entry" + error_entry);
+        string error_entry((_T(" '") + name + _T("'")).mb_str());
+        string error_context(" failed for entry" + error_entry);
 
         TestEntries::iterator it = m_testEntries.find(name);
         CPPUNIT_ASSERT_MESSAGE(
@@ -975,8 +813,8 @@ void ArchiveTestCase<Classes>::ExtractArchive(wxInputStream& in)
             testEntry.GetLength() == entry->GetSize() ||
             ((m_options & PipeIn) != 0 && entry->GetSize() == wxInvalidOffset));
         CPPUNIT_ASSERT_MESSAGE(
-            "arc->GetSize() == entry->GetSize()" + error_context,
-            arc->GetSize() == (size_t)entry->GetSize());
+            "arc->GetLength() == entry->GetSize()" + error_context,
+            arc->GetLength() == entry->GetSize());
 
         if (name.Last() != _T('/'))
         {
@@ -998,8 +836,8 @@ void ArchiveTestCase<Classes>::ExtractArchive(wxInputStream& in)
         CPPUNIT_ASSERT_MESSAGE("entry size check" + error_context,
             testEntry.GetLength() == entry->GetSize());
         CPPUNIT_ASSERT_MESSAGE(
-            "arc->GetSize() == entry->GetSize()" + error_context,
-            arc->GetSize() == (size_t)entry->GetSize());
+            "arc->GetLength() == entry->GetSize()" + error_context,
+            arc->GetLength() == entry->GetSize());
 
         if ((m_options & PipeIn) == 0) {
             OnEntryExtracted(*entry, testEntry, arc.get());
@@ -1029,9 +867,9 @@ void ArchiveTestCase<Classes>::ExtractArchive(wxInputStream& in)
 
 // Extract an archive using an external unarchive program
 //
-template <class Classes>
-void ArchiveTestCase<Classes>::ExtractArchive(wxInputStream& in,
-                                              const wxString& unarchiver)
+template <class ClassFactoryT>
+void ArchiveTestCase<ClassFactoryT>::ExtractArchive(wxInputStream& in,
+                                                    const wxString& unarchiver)
 {
     // for an external unarchiver, unarchive to a tempdir
     TempDir tmpdir;
@@ -1039,10 +877,10 @@ void ArchiveTestCase<Classes>::ExtractArchive(wxInputStream& in,
     if ((m_options & PipeIn) == 0) {
         wxFileName fn(tmpdir.GetName());
         fn.SetExt(_T("arc"));
-        wxString tmparc = fn.GetFullPath();
-        
+        wxString tmparc = fn.GetPath(wxPATH_GET_SEPARATOR) + fn.GetFullName();
+
         if (m_options & Stub)
-            in.SeekI(TestOutputStream::STUB_SIZE * 2);
+            in.SeekI(STUB_SIZE * 2);
 
         // write the archive to a temporary file
         {
@@ -1069,8 +907,9 @@ void ArchiveTestCase<Classes>::ExtractArchive(wxInputStream& in,
 
 // Verifies the files produced by an external unarchiver are as expected
 //
-template <class Classes>
-void ArchiveTestCase<Classes>::VerifyDir(wxString& path, size_t rootlen /*=0*/)
+template <class ClassFactoryT>
+void ArchiveTestCase<ClassFactoryT>::VerifyDir(wxString& path,
+                                               size_t rootlen /*=0*/)
 {
     wxDir dir;
     path += wxFileName::GetPathSeparator();
@@ -1092,8 +931,8 @@ void ArchiveTestCase<Classes>::VerifyDir(wxString& path, size_t rootlen /*=0*/)
 
             // provide some context for the error message so that we know which
             // iteration of the loop we were on
-            std::string error_entry((_T(" '") + name + _T("'")).mb_str());
-            std::string error_context(" failed for entry" + error_entry);
+            string error_entry((_T(" '") + name + _T("'")).mb_str());
+            string error_context(" failed for entry" + error_entry);
 
             TestEntries::iterator it = m_testEntries.find(name);
             CPPUNIT_ASSERT_MESSAGE(
@@ -1102,9 +941,8 @@ void ArchiveTestCase<Classes>::VerifyDir(wxString& path, size_t rootlen /*=0*/)
                 it != m_testEntries.end());
 
             const TestEntry& testEntry = *it->second;
-            size_t size = 0;
 
-#ifndef __WXMSW__
+#if 0 //ndef __WXMSW__
             CPPUNIT_ASSERT_MESSAGE("timestamp check" + error_context,
                                    testEntry.GetDateTime() ==
                                    wxFileName(path).GetModificationTime());
@@ -1114,7 +952,7 @@ void ArchiveTestCase<Classes>::VerifyDir(wxString& path, size_t rootlen /*=0*/)
                 CPPUNIT_ASSERT_MESSAGE(
                     "entry not found in archive" + error_entry, in.Ok());
 
-                size = in.GetSize();
+                size_t size = (size_t)in.GetLength();
                 wxCharBuffer buf(size);
                 CPPUNIT_ASSERT_MESSAGE("Read" + error_context,
                     in.Read(buf.data(), size).LastRead() == size);
@@ -1136,13 +974,13 @@ void ArchiveTestCase<Classes>::VerifyDir(wxString& path, size_t rootlen /*=0*/)
 
 // test the simple iterators that give away ownership of an entry
 //
-template <class Classes>
-void ArchiveTestCase<Classes>::TestIterator(wxInputStream& in)
+template <class ClassFactoryT>
+void ArchiveTestCase<ClassFactoryT>::TestIterator(wxInputStream& in)
 {
     typedef std::list<EntryT*> ArchiveCatalog;
     typedef typename ArchiveCatalog::iterator CatalogIter;
 
-    std::auto_ptr<InputStreamT> arc(m_factory->NewStream(in));
+    auto_ptr<InputStreamT> arc(m_factory->NewStream(in));
     size_t count = 0;
 
 #ifdef WXARC_MEMBER_TEMPLATES
@@ -1154,7 +992,7 @@ void ArchiveTestCase<Classes>::TestIterator(wxInputStream& in)
 #endif
 
     for (CatalogIter it = cat.begin(); it != cat.end(); ++it) {
-        std::auto_ptr<EntryT> entry(*it);
+        auto_ptr<EntryT> entry(*it);
         count += m_testEntries.count(entry->GetName(wxPATH_UNIX));
     }
 
@@ -1165,13 +1003,13 @@ void ArchiveTestCase<Classes>::TestIterator(wxInputStream& in)
 // test the pair iterators that can be used to load a std::map or wxHashMap
 // these also give away ownership of entries
 //
-template <class Classes>
-void ArchiveTestCase<Classes>::TestPairIterator(wxInputStream& in)
+template <class ClassFactoryT>
+void ArchiveTestCase<ClassFactoryT>::TestPairIterator(wxInputStream& in)
 {
     typedef std::map<wxString, EntryT*> ArchiveCatalog;
     typedef typename ArchiveCatalog::iterator CatalogIter;
 
-    std::auto_ptr<InputStreamT> arc(m_factory->NewStream(in));
+    auto_ptr<InputStreamT> arc(m_factory->NewStream(in));
     size_t count = 0;
 
 #ifdef WXARC_MEMBER_TEMPLATES
@@ -1179,11 +1017,11 @@ void ArchiveTestCase<Classes>::TestPairIterator(wxInputStream& in)
 #else
     ArchiveCatalog cat;
     for (PairIterT i(*arc); i != PairIterT(); ++i)
-        cat.push_back(*i);
+        cat.insert(*i);
 #endif
 
     for (CatalogIter it = cat.begin(); it != cat.end(); ++it) {
-        std::auto_ptr<EntryT> entry(it->second);
+        auto_ptr<EntryT> entry(it->second);
         count += m_testEntries.count(entry->GetName(wxPATH_UNIX));
     }
 
@@ -1193,14 +1031,14 @@ void ArchiveTestCase<Classes>::TestPairIterator(wxInputStream& in)
 
 // simple iterators using smart pointers, no need to worry about ownership
 //
-template <class Classes>
-void ArchiveTestCase<Classes>::TestSmartIterator(wxInputStream& in)
+template <class ClassFactoryT>
+void ArchiveTestCase<ClassFactoryT>::TestSmartIterator(wxInputStream& in)
 {
     typedef std::list<Ptr<EntryT> > ArchiveCatalog;
     typedef typename ArchiveCatalog::iterator CatalogIter;
     typedef wxArchiveIterator<InputStreamT, Ptr<EntryT> > Iter;
 
-    std::auto_ptr<InputStreamT> arc(m_factory->NewStream(in));
+    auto_ptr<InputStreamT> arc(m_factory->NewStream(in));
 
 #ifdef WXARC_MEMBER_TEMPLATES
     ArchiveCatalog cat((Iter)*arc, Iter());
@@ -1218,34 +1056,40 @@ void ArchiveTestCase<Classes>::TestSmartIterator(wxInputStream& in)
 
 // pair iterator using smart pointers
 //
-template <class Classes>
-void ArchiveTestCase<Classes>::TestSmartPairIterator(wxInputStream& in)
+template <class ClassFactoryT>
+void ArchiveTestCase<ClassFactoryT>::TestSmartPairIterator(wxInputStream& in)
 {
+#if defined _MSC_VER && defined _MSC_VER < 1200
+    // With VC++ 5.0 the '=' operator of std::pair breaks when the second
+    // type is Ptr<EntryT>, so this iterator can't be made to work.
+    (void)in;
+#else
     typedef std::map<wxString, Ptr<EntryT> > ArchiveCatalog;
     typedef typename ArchiveCatalog::iterator CatalogIter;
     typedef wxArchiveIterator<InputStreamT,
                 std::pair<wxString, Ptr<EntryT> > > PairIter;
 
-    std::auto_ptr<InputStreamT> arc(m_factory->NewStream(in));
+    auto_ptr<InputStreamT> arc(m_factory->NewStream(in));
 
 #ifdef WXARC_MEMBER_TEMPLATES
     ArchiveCatalog cat((PairIter)*arc, PairIter());
 #else
     ArchiveCatalog cat;
     for (PairIter i(*arc); i != PairIter(); ++i)
-        cat.push_back(*i);
+        cat.insert(*i);
 #endif
 
     CPPUNIT_ASSERT(m_testEntries.size() == cat.size());
 
     for (CatalogIter it = cat.begin(); it != cat.end(); ++it)
         CPPUNIT_ASSERT(m_testEntries.count(it->second->GetName(wxPATH_UNIX)));
+#endif
 }
 
 // try reading two entries at the same time
 //
-template <class Classes>
-void ArchiveTestCase<Classes>::ReadSimultaneous(TestInputStream& in)
+template <class ClassFactoryT>
+void ArchiveTestCase<ClassFactoryT>::ReadSimultaneous(TestInputStream& in)
 {
     typedef std::map<wxString, Ptr<EntryT> > ArchiveCatalog;
     typedef wxArchiveIterator<InputStreamT,
@@ -1253,8 +1097,8 @@ void ArchiveTestCase<Classes>::ReadSimultaneous(TestInputStream& in)
 
     // create two archive input streams
     TestInputStream in2(in);
-    std::auto_ptr<InputStreamT> arc(m_factory->NewStream(in));
-    std::auto_ptr<InputStreamT> arc2(m_factory->NewStream(in2));
+    auto_ptr<InputStreamT> arc(m_factory->NewStream(in));
+    auto_ptr<InputStreamT> arc2(m_factory->NewStream(in2));
 
     // load the catalog
 #ifdef WXARC_MEMBER_TEMPLATES
@@ -1262,7 +1106,7 @@ void ArchiveTestCase<Classes>::ReadSimultaneous(TestInputStream& in)
 #else
     ArchiveCatalog cat;
     for (PairIter i(*arc); i != PairIter(); ++i)
-        cat.push_back(*i);
+        cat.insert(*i);
 #endif
 
     // the names of two entries to read
@@ -1317,8 +1161,8 @@ public:
     void OnEntryUpdated(EntryT& WXUNUSED(entry)) { }
 };
 
-template <class Classes>
-void ArchiveTestCase<Classes>::OnSetNotifier(EntryT& entry)
+template <class ClassFactoryT>
+void ArchiveTestCase<ClassFactoryT>::OnSetNotifier(EntryT& entry)
 {
     static ArchiveNotifier<NotifierT, EntryT> notifier;
     entry.SetNotifier(notifier);
@@ -1326,210 +1170,115 @@ void ArchiveTestCase<Classes>::OnSetNotifier(EntryT& entry)
 
 
 ///////////////////////////////////////////////////////////////////////////////
-// ArchiveTestCase<ZipClasses> could be used directly, but instead this
-// derived class is used so that zip specific features can be tested.
+// An additional case to check that reading corrupt archives doesn't crash
 
-class ZipTestCase : public ArchiveTestCase<ZipClasses>
+class CorruptionTestCase : public CppUnit::TestCase
 {
 public:
-    ZipTestCase(const wxString& name,
-                int id,
-                int options,
-                const wxString& archiver = wxEmptyString,
-                const wxString& unarchiver = wxEmptyString)
-    :
-        ArchiveTestCase<ZipClasses>(name, id, new wxZipClassFactory,
-                                    options, archiver, unarchiver),
-        m_count(0)
+    CorruptionTestCase(std::string name,
+                       wxArchiveClassFactory *factory,
+                       int options)
+      : CppUnit::TestCase(TestId::MakeId() + name),
+        m_factory(factory),
+        m_options(options)
     { }
 
 protected:
-    void OnCreateArchive(wxZipOutputStream& zip);
-    
-    void OnArchiveExtracted(wxZipInputStream& zip, int expectedTotal);
-    
-    void OnCreateEntry(wxZipOutputStream& zip,
-                       TestEntry& testEntry,
-                       wxZipEntry *entry);
-    
-    void OnEntryExtracted(wxZipEntry& entry,
-                          const TestEntry& testEntry,
-                          wxZipInputStream *arc);
-
-    void OnSetNotifier(EntryT& entry);
-
-    int m_count;
-    wxString m_comment;
-};
+    // the entry point for the test
+    void runTest();
 
-void ZipTestCase::OnCreateArchive(wxZipOutputStream& zip)
-{
-    m_comment << _T("Comment for test ") << m_id;
-    zip.SetComment(m_comment);
-}
+    void CreateArchive(wxOutputStream& out);
+    void ExtractArchive(wxInputStream& in);
 
-void ZipTestCase::OnArchiveExtracted(wxZipInputStream& zip, int expectedTotal)
-{
-    CPPUNIT_ASSERT(zip.GetComment() == m_comment);
-    CPPUNIT_ASSERT(zip.GetTotalEntries() == expectedTotal);
-}
+    auto_ptr<wxArchiveClassFactory> m_factory;  // factory to make classes
+    int m_options;                              // test options
+};
 
-void ZipTestCase::OnCreateEntry(wxZipOutputStream& zip,
-                                TestEntry& testEntry,
-                                wxZipEntry *entry)
+void CorruptionTestCase::runTest()
 {
-    zip.SetLevel((m_id + m_count) % 10);
-
-    if (entry) {
-        switch ((m_id + m_count) % 5) {
-            case 0:
-            {
-                wxString comment = _T("Comment for ") + entry->GetName();
-                entry->SetComment(comment);
-                // lowercase the expected result, and the notifier should do
-                // the same for the zip entries when ModifyArchive() runs
-                testEntry.SetComment(comment.Lower());
-                break;
-            }
-            case 2:
-                entry->SetMethod(wxZIP_METHOD_STORE);
-                break;
-            case 4:
-                entry->SetMethod(wxZIP_METHOD_DEFLATE);
-                break;
-        }
-        entry->SetIsText(testEntry.IsText());
+    TestOutputStream out(m_options);
+    CreateArchive(out);
+    TestInputStream in(out, 0);
+    wxFileOffset len = in.GetLength();
+
+    // try flipping one byte in the archive
+    int pos;
+    for (pos = 0; pos < len; pos++) {
+        char n = in[pos];
+        in[pos] = ~n;
+        ExtractArchive(in);
+        in.Rewind();
+        in[pos] = n;
     }
 
-    m_count++;
-}
-
-void ZipTestCase::OnEntryExtracted(wxZipEntry& entry,
-                                   const TestEntry& testEntry,
-                                   wxZipInputStream *arc)
-{
-    // provide some context for the error message so that we know which
-    // iteration of the loop we were on
-    std::string error_entry((_T(" '") + entry.GetName() + _T("'")).mb_str());
-    std::string error_context(" failed for entry" + error_entry);
-
-    CPPUNIT_ASSERT_MESSAGE("GetComment" + error_context,
-        entry.GetComment() == testEntry.GetComment());
-
-    // for seekable streams, GetNextEntry() doesn't read the local header so
-    // call OpenEntry() to do it
-    if (arc && (m_options & PipeIn) == 0 && entry.IsDir())
-        arc->OpenEntry(entry);
-
-    CPPUNIT_ASSERT_MESSAGE("IsText" + error_context,
-                           entry.IsText() == testEntry.IsText());
+    // try zeroing one byte in the archive
+    for (pos = 0; pos < len; pos++) {
+        char n = in[pos];
+        in[pos] = 0;
+        ExtractArchive(in);
+        in.Rewind();
+        in[pos] = n;
+    }
 
-    CPPUNIT_ASSERT_MESSAGE("Extra/LocalExtra mismatch for entry" + error_entry,
-        (entry.GetExtraLen() != 0 && entry.GetLocalExtraLen() != 0) ||
-        (entry.GetExtraLen() == 0 && entry.GetLocalExtraLen() == 0));
+    // try chopping the archive off
+    for (int size = 1; size <= len; size++) {
+        in.Chop(size);
+        ExtractArchive(in);
+        in.Rewind();
+    }
 }
 
-// check the notifier mechanism by using it to fold the entry comments to
-// lowercase
-//
-class ZipNotifier : public wxZipNotifier
+void CorruptionTestCase::CreateArchive(wxOutputStream& out)
 {
-public:
-    void OnEntryUpdated(wxZipEntry& entry);
-};
+    auto_ptr<wxArchiveOutputStream> arc(m_factory->NewStream(out));
 
-void ZipNotifier::OnEntryUpdated(wxZipEntry& entry)
-{
-    entry.SetComment(entry.GetComment().Lower());
+    arc->PutNextDirEntry(_T("dir"));
+    arc->PutNextEntry(_T("file"));
+    arc->Write(_T("foo"), 3);
 }
 
-void ZipTestCase::OnSetNotifier(EntryT& entry)
+void CorruptionTestCase::ExtractArchive(wxInputStream& in)
 {
-    static ZipNotifier notifier;
-    entry.SetNotifier(notifier);
+    auto_ptr<wxArchiveInputStream> arc(m_factory->NewStream(in));
+    auto_ptr<wxArchiveEntry> entry(arc->GetNextEntry());
+        
+    while (entry.get() != NULL) {
+        wxString name = entry->GetName();
+        char buf[1024];
+        
+        while (arc->IsOk())
+            arc->Read(buf, sizeof(buf));
+
+        auto_ptr<wxArchiveEntry> next(arc->GetNextEntry());
+        entry = next;
+    }
 }
 
 
 ///////////////////////////////////////////////////////////////////////////////
-// 'zip - -' produces local headers without the size field set. This is a
-// case not covered by all the other tests, so this class tests it as a
-// special case
+// Make the ids
 
-class ZipPipeTestCase : public CppUnit::TestCase
-{
-public:
-    ZipPipeTestCase(const wxString& name, int options) :
-        CppUnit::TestCase(std::string(name.mb_str())), m_options(options) { }
+int TestId::m_seed = 6219;
 
-protected:
-    void runTest();
-    int m_options;
-};
-
-void ZipPipeTestCase::runTest()
+// static
+string TestId::MakeId()
 {
-    TestOutputStream out(m_options);
-
-    wxString testdata = _T("test data to pipe through zip");
-    wxString cmd = _T("echo ") + testdata + _T(" | zip -q - -");
-
-    {
-        PFileInputStream in(cmd);
-        if (in.Ok())
-            out.Write(in);
-    }
-
-    TestInputStream in(out);
-    wxZipInputStream zip(in);
-
-    std::auto_ptr<wxZipEntry> entry(zip.GetNextEntry());
-    CPPUNIT_ASSERT(entry.get() != NULL);
-
-    if ((m_options & PipeIn) == 0)
-        CPPUNIT_ASSERT(entry->GetSize() != wxInvalidOffset);
-
-    char buf[64];
-    size_t len = zip.Read(buf, sizeof(buf) - 1).LastRead();
-
-    while (len > 0 && buf[len - 1] <= 32)
-        --len;
-    buf[len] = 0;
-
-    CPPUNIT_ASSERT(zip.Eof());
-    CPPUNIT_ASSERT(wxString(buf, *wxConvCurrent) == testdata);
+    m_seed = (m_seed * 171) % 30269;
+    return string(wxString::Format(_T("%-6d"), m_seed).mb_str());
 }
 
 
 ///////////////////////////////////////////////////////////////////////////////
-// The suite
+// Suite base
 
-class ArchiveTestSuite : public CppUnit::TestSuite
-{
-public:
-    ArchiveTestSuite();
-    static CppUnit::Test *suite()
-        { return (new ArchiveTestSuite)->makeSuite(); }
-
-private:
-    int m_id;
-    wxPathList m_path;
-
-    ArchiveTestSuite *makeSuite();
-    void AddCmd(wxArrayString& cmdlist, const wxString& cmd);
-    bool IsInPath(const wxString& cmd);
-
-    wxString Description(const wxString& type,
-                         int options,
-                         bool genericInterface = false,
-                         const wxString& archiver = wxEmptyString,
-                         const wxString& unarchiver = wxEmptyString);
-};
-
-ArchiveTestSuite::ArchiveTestSuite()
-  : CppUnit::TestSuite("ArchiveTestSuite"),
-    m_id(0)
+ArchiveTestSuite::ArchiveTestSuite(string name)
+  : CppUnit::TestSuite("archive/" + name),
+    m_name(name.c_str(), *wxConvCurrent)
 {
+    m_name = _T("wx") + m_name.Left(1).Upper() + m_name.Mid(1).Lower();
     m_path.AddEnvList(_T("PATH"));
+    m_archivers.push_back(_T(""));
+    m_unarchivers.push_back(_T(""));
 }
 
 // add the command for an external archiver to the list, testing for it in
@@ -1537,8 +1286,6 @@ ArchiveTestSuite::ArchiveTestSuite()
 //
 void ArchiveTestSuite::AddCmd(wxArrayString& cmdlist, const wxString& cmd)
 {
-    if (cmdlist.empty())
-        cmdlist.push_back(_T(""));
     if (IsInPath(cmd))
         cmdlist.push_back(cmd);
 }
@@ -1557,73 +1304,83 @@ bool ArchiveTestSuite::IsInPath(const wxString& cmd)
 ArchiveTestSuite *ArchiveTestSuite::makeSuite()
 {
     typedef wxArrayString::iterator Iter;
-    wxArrayString zippers;
-    wxArrayString unzippers;
-
-    AddCmd(zippers, _T("zip -qr %s *"));
-    AddCmd(unzippers, _T("unzip -q %s"));
 
-    for (int genInterface = 0; genInterface < 2; genInterface++)
-        for (Iter i = unzippers.begin(); i != unzippers.end(); ++i)
-            for (Iter j = zippers.begin(); j != zippers.end(); ++j)
+    for (int generic = 0; generic < 2; generic++)
+        for (Iter i = m_unarchivers.begin(); i != m_unarchivers.end(); ++i)
+            for (Iter j = m_archivers.begin(); j != m_archivers.end(); ++j)
                 for (int options = 0; options <= AllOptions; options++)
                 {
-                    // unzip doesn't support piping in the zip
+#ifdef WXARC_NO_POPEN
+                    // if no popen then can't pipe in/out of archiver
                     if ((options & PipeIn) && !i->empty())
                         continue;
-#ifdef WXARC_NO_POPEN 
-                    // if no popen then can use piped output of zip
                     if ((options & PipeOut) && !j->empty())
                         continue;
 #endif
-                    wxString name = Description(_T("wxZip"), options, 
-                                                genInterface != 0, *j, *i);
-
-                    if (genInterface)
-                        addTest(new ArchiveTestCase<ArchiveClasses>(
-                                    name, m_id,
-                                    new wxZipClassFactory,
-                                    options, *j, *i));
-                    else
-                        addTest(new ZipTestCase(name, m_id, options, *j, *i));
-
-                    m_id++;
+                    string descr = Description(m_name, options,
+                                               generic != 0, *j, *i);
+
+                    CppUnit::Test *test = makeTest(descr, options,
+                                                   generic != 0, *j, *i);
+
+                    if (test)
+                        addTest(test);
                 }
 
-#ifndef WXARC_NO_POPEN 
-    // if have popen then can check the piped output of 'zip - -'
-    if (IsInPath(_T("zip")))
-        for (int options = 0; options <= PipeIn; options += PipeIn) {
-            wxString name = Description(_T("ZipPipeTestCase"), options);
-            addTest(new ZipPipeTestCase(name, options));
-            m_id++;
+    for (int options = 0; options <= PipeIn; options += PipeIn) 
+    {
+        wxObject *pObj = wxCreateDynamicObject(m_name + _T("ClassFactory"));
+        wxArchiveClassFactory *factory;
+        factory = wxDynamicCast(pObj, wxArchiveClassFactory);
+
+        if (factory) {
+            string descr(m_name.mb_str());
+            descr = "CorruptionTestCase (" + descr + ")";
+
+            if (options)
+                descr += " (PipeIn)";
+
+            addTest(new CorruptionTestCase(descr, factory, options));
         }
-#endif
+    }
 
     return this;
 }
 
+CppUnit::Test *ArchiveTestSuite::makeTest(
+    string WXUNUSED(descr),
+    int WXUNUSED(options),
+    bool WXUNUSED(genericInterface),
+    const wxString& WXUNUSED(archiver),
+    const wxString& WXUNUSED(unarchiver))
+{
+    return NULL;
+}
+
 // make a display string for the option bits
 //
-wxString ArchiveTestSuite::Description(const wxString& type,
-                                       int options,
-                                       bool genericInterface,
-                                       const wxString& archiver,
-                                       const wxString& unarchiver)
+string ArchiveTestSuite::Description(const wxString& type,
+                                     int options,
+                                     bool genericInterface,
+                                     const wxString& archiver,
+                                     const wxString& unarchiver)
 {
     wxString descr;
-    descr << m_id << _T(" ");
-    
+
     if (genericInterface)
         descr << _T("wxArchive (") << type << _T(")");
     else
         descr << type;
 
-    if (!archiver.empty())
-        descr << _T(" ") << archiver.BeforeFirst(_T(' '));
-    if (!unarchiver.empty())
-        descr << _T(" ") << unarchiver.BeforeFirst(_T(' '));
-    
+    if (!archiver.empty()) {
+        const wxChar *fn = (options & PipeOut) != 0 ? _T("-") : _T("file");
+        descr << _T(" (") << wxString::Format(archiver, fn) << _T(")");
+    }
+    if (!unarchiver.empty()) {
+        const wxChar *fn = (options & PipeIn) != 0 ? _T("-") : _T("file");
+        descr << _T(" (") << wxString::Format(unarchiver, fn) << _T(")");
+    }
+
     wxString optstr;
 
     if ((options & PipeIn) != 0)
@@ -1637,13 +1394,23 @@ wxString ArchiveTestSuite::Description(const wxString& type,
 
     descr << optstr;
 
-    return descr;
+    return string(descr.mb_str());
 }
 
-// register in the unnamed registry so that these tests are run by default
-CPPUNIT_TEST_SUITE_REGISTRATION(ArchiveTestSuite);
 
-// also include in it's own registry so that these tests can be run alone
-CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(ArchiveTestSuite, "ArchiveTestSuite");
+///////////////////////////////////////////////////////////////////////////////
+// Instantiations
+
+template class ArchiveTestCase<wxArchiveClassFactory>;
+
+#if wxUSE_ZIPSTREAM
+#include "wx/zipstrm.h"
+template class ArchiveTestCase<wxZipClassFactory>;
+#endif
+
+#if wxUSE_TARSTREAM
+#include "wx/tarstrm.h"
+template class ArchiveTestCase<wxTarClassFactory>;
+#endif
 
-#endif // wxUSE_STREAMS
+#endif // wxUSE_STREAMS && wxUSE_ARCHIVE_STREAMS