+///////////////////////////////////////////////////////////////////////////////
+// Name:        tests/archive/archivetest.h
+// Purpose:     Test the archive classes
+// Author:      Mike Wetherell
+// RCS-ID:      $Id$
+// Copyright:   (c) 2004 Mike Wetherell
+// Licence:     wxWindows licence
+///////////////////////////////////////////////////////////////////////////////
+
+#define WX_TEST_ARCHIVE_ITERATOR
+
+#include "wx/archive.h"
+#include "wx/wfstream.h"
+
+
+///////////////////////////////////////////////////////////////////////////////
+// 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
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// 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; }
+    wxFileOffset GetLength() const { return m_size; }
+
+    // gives away the data, this stream is then empty, and can be reused
+    void GetData(char*& data, size_t& size);
+
+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;
+};
+
+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();
+    wxFileOffset GetLength() 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;
+    char *m_data;
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// wxFFile streams for piping to/from an external program
+
+class PFileInputStream : public wxFFileInputStream
+{
+public:
+    PFileInputStream(const wxString& cmd);
+    ~PFileInputStream();
+};
+
+class PFileOutputStream : public wxFFileOutputStream
+{
+public:
+    PFileOutputStream(const wxString& cmd);
+    ~PFileOutputStream();
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// 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;
+    char *m_data;
+    wxString m_comment;
+    bool m_isText;
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// The test case
+
+template <class ClassFactoryT>
+class ArchiveTestCase : public CppUnit::TestCase
+{
+public:
+    ArchiveTestCase(std::string name,
+                    int id,
+                    ClassFactoryT *factory,
+                    int options,
+                    const wxString& archiver = wxEmptyString,
+                    const wxString& unarchiver = wxEmptyString);
+
+    ~ArchiveTestCase();
+
+protected:
+    // the classes to test
+    typedef typename ClassFactoryT::entry_type     EntryT;
+    typedef typename ClassFactoryT::instream_type  InputStreamT;
+    typedef typename ClassFactoryT::outstream_type OutputStreamT;
+    typedef typename ClassFactoryT::notifier_type  NotifierT;
+    typedef typename ClassFactoryT::iter_type      IterT;
+    typedef typename ClassFactoryT::pairiter_type  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);
+
+    // 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
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Base class for the archive test suites
+
+class ArchiveTestSuite : public CppUnit::TestSuite
+{
+public:
+    ArchiveTestSuite(std::string name);
+
+protected:
+    int m_id;
+
+    virtual ArchiveTestSuite *makeSuite();
+
+    virtual CppUnit::Test *makeTest(std::string descr,
+                                    int id,
+                                    int options,
+                                    bool genericInterface,
+                                    const wxString& archiver,
+                                    const wxString& unarchiver);
+
+    void AddArchiver(const wxString& cmd) { AddCmd(m_archivers, cmd); }
+    void AddUnArchiver(const wxString &cmd) { AddCmd(m_unarchivers, cmd); }
+    bool IsInPath(const wxString& cmd);
+
+    std::string Description(const wxString& type,
+                            int options,
+                            bool genericInterface = false,
+                            const wxString& archiver = wxEmptyString,
+                            const wxString& unarchiver = wxEmptyString);
+
+private:
+    wxString m_name;
+    wxPathList m_path;
+    wxArrayString m_archivers;
+    wxArrayString m_unarchivers;
+
+    void AddCmd(wxArrayString& cmdlist, const wxString& cmd);
+};