1///////////////////////////////////////////////////////////////////////////////
2// Name:        tests/archive/archivetest.h
3// Purpose:     Test the archive classes
4// Author:      Mike Wetherell
5// RCS-ID:      $Id: archivetest.h 41411 2006-09-24 11:52:53Z MW $
6// Copyright:   (c) 2004 Mike Wetherell
7// Licence:     wxWindows licence
8///////////////////////////////////////////////////////////////////////////////
9
10#define WX_TEST_ARCHIVE_ITERATOR
11
12#include "wx/archive.h"
13#include "wx/wfstream.h"
14
15
16///////////////////////////////////////////////////////////////////////////////
17// Bit flags for options for the tests
18
19enum Options
20{
21    PipeIn      = 0x01,     // input streams are non-seekable
22    PipeOut     = 0x02,     // output streams are non-seekable
23    Stub        = 0x04,     // the archive should be appended to a stub
24    AllOptions  = 0x07
25};
26
27
28///////////////////////////////////////////////////////////////////////////////
29// TestOutputStream and TestInputStream are memory streams which can be
30// seekable or non-seekable.
31
32class TestOutputStream : public wxOutputStream
33{
34public:
35    TestOutputStream(int options);
36
37    ~TestOutputStream() { delete [] m_data; }
38
39    int GetOptions() const { return m_options; }
40    wxFileOffset GetLength() const { return m_size; }
41    bool IsSeekable() const { return (m_options & PipeOut) == 0; }
42
43    // gives away the data, this stream is then empty, and can be reused
44    void GetData(char*& data, size_t& size);
45
46private:
47    void Init();
48
49    wxFileOffset OnSysSeek(wxFileOffset pos, wxSeekMode mode);
50    wxFileOffset OnSysTell() const;
51    size_t OnSysWrite(const void *buffer, size_t size);
52
53    int m_options;
54    size_t m_pos;
55    size_t m_capacity;
56    size_t m_size;
57    char *m_data;
58};
59
60class TestInputStream : public wxInputStream
61{
62public:
63    // various streams have implemented eof differently, so check the archive
64    // stream works with all the possibilities (bit flags that can be ORed)
65    enum EofTypes {
66        AtLast    = 0x01,   // eof before an attempt to read past the last byte
67        WithError = 0x02    // give an error instead of eof
68    };
69
70    // ctor takes the data from the output stream, which is then empty
71    TestInputStream(TestOutputStream& out, int eoftype)
72        : m_data(NULL), m_eoftype(eoftype) { SetData(out); }
73    // this ctor 'dups'
74    TestInputStream(const TestInputStream& in);
75    ~TestInputStream() { delete [] m_data; }
76
77    void Rewind();
78    wxFileOffset GetLength() const { return m_size; }
79    bool IsSeekable() const { return (m_options & PipeIn) == 0; }
80    void SetData(TestOutputStream& out);
81
82    void Chop(size_t size) { m_size = size; }
83    char& operator [](size_t pos) { return m_data[pos]; }
84
85private:
86    wxFileOffset OnSysSeek(wxFileOffset pos, wxSeekMode mode);
87    wxFileOffset OnSysTell() const;
88    size_t OnSysRead(void *buffer, size_t size);
89
90    int m_options;
91    size_t m_pos;
92    size_t m_size;
93    char *m_data;
94    int m_eoftype;
95};
96
97
98///////////////////////////////////////////////////////////////////////////////
99// wxFFile streams for piping to/from an external program
100
101class PFileInputStream : public wxFFileInputStream
102{
103public:
104    PFileInputStream(const wxString& cmd);
105    ~PFileInputStream();
106};
107
108class PFileOutputStream : public wxFFileOutputStream
109{
110public:
111    PFileOutputStream(const wxString& cmd);
112    ~PFileOutputStream();
113};
114
115
116///////////////////////////////////////////////////////////////////////////////
117// A class to hold a test entry
118
119class TestEntry
120{
121public:
122    TestEntry(const wxDateTime& dt, int len, const char *data);
123    ~TestEntry() { delete [] m_data; }
124
125    wxDateTime GetDateTime() const  { return m_dt; }
126    wxFileOffset GetLength() const  { return m_len; }
127    size_t GetSize() const          { return m_len; }
128    const char *GetData() const     { return m_data; }
129    wxString GetComment() const     { return m_comment; }
130    bool IsText() const             { return m_isText; }
131
132    void SetComment(const wxString& comment) { m_comment = comment; }
133    void SetDateTime(const wxDateTime& dt)   { m_dt = dt; }
134
135private:
136    wxDateTime m_dt;
137    size_t m_len;
138    char *m_data;
139    wxString m_comment;
140    bool m_isText;
141};
142
143
144///////////////////////////////////////////////////////////////////////////////
145// The test case
146
147template <class ClassFactoryT>
148class ArchiveTestCase : public CppUnit::TestCase
149{
150public:
151    ArchiveTestCase(std::string name,
152                    ClassFactoryT *factory,
153                    int options,
154                    const wxString& archiver = wxEmptyString,
155                    const wxString& unarchiver = wxEmptyString);
156
157    ~ArchiveTestCase();
158
159protected:
160    // the classes to test
161    typedef typename ClassFactoryT::entry_type     EntryT;
162    typedef typename ClassFactoryT::instream_type  InputStreamT;
163    typedef typename ClassFactoryT::outstream_type OutputStreamT;
164    typedef typename ClassFactoryT::notifier_type  NotifierT;
165    typedef typename ClassFactoryT::iter_type      IterT;
166    typedef typename ClassFactoryT::pairiter_type  PairIterT;
167
168    // the entry point for the test
169    void runTest();
170
171    // create the test data
172    void CreateTestData();
173    TestEntry& Add(const char *name, const char *data, int len = -1);
174    TestEntry& Add(const char *name, int len = 0, int value = EOF);
175
176    // 'archive up' the test data
177    void CreateArchive(wxOutputStream& out);
178    void CreateArchive(wxOutputStream& out, const wxString& archiver);
179
180    // perform various modifications on the archive
181    void ModifyArchive(wxInputStream& in, wxOutputStream& out);
182
183    // extract the archive and verify its contents
184    void ExtractArchive(wxInputStream& in);
185    void ExtractArchive(wxInputStream& in, const wxString& unarchiver);
186    void VerifyDir(wxString& path, size_t rootlen = 0);
187
188    // tests for the iterators
189    void TestIterator(wxInputStream& in);
190    void TestPairIterator(wxInputStream& in);
191    void TestSmartIterator(wxInputStream& in);
192    void TestSmartPairIterator(wxInputStream& in);
193
194    // try reading two entries at the same time
195    void ReadSimultaneous(TestInputStream& in);
196
197    // overridables
198    virtual void OnCreateArchive(OutputStreamT& WXUNUSED(arc)) { }
199    virtual void OnSetNotifier(EntryT& entry);
200
201    virtual void OnArchiveExtracted(InputStreamT& WXUNUSED(arc),
202                                    int WXUNUSED(expectedTotal)) { }
203
204    virtual void OnCreateEntry(     OutputStreamT& WXUNUSED(arc),
205                                    TestEntry& WXUNUSED(testEntry),
206                                    EntryT *entry = NULL) { (void)entry; }
207
208    virtual void OnEntryExtracted(  EntryT& WXUNUSED(entry),
209                                    const TestEntry& WXUNUSED(testEntry),
210                                    InputStreamT *arc = NULL) { (void)arc; }
211
212    typedef std::map<wxString, TestEntry*> TestEntries;
213    TestEntries m_testEntries;              // test data
214    std::auto_ptr<ClassFactoryT> m_factory; // factory to make classes
215    int m_options;                          // test options
216    wxDateTime m_timeStamp;                 // timestamp to give test entries
217    int m_id;                               // select between the possibilites
218    wxString m_archiver;                    // external archiver
219    wxString m_unarchiver;                  // external unarchiver
220};
221
222
223///////////////////////////////////////////////////////////////////////////////
224// Make ids
225
226class TestId
227{
228public:
229    // make a new id and return it as a string
230    static std::string MakeId();
231    // get the current id
232    static int GetId() { return m_seed; }
233private:
234    // seed for generating the ids
235    static int m_seed;
236};
237
238
239///////////////////////////////////////////////////////////////////////////////
240// Base class for the archive test suites
241
242class ArchiveTestSuite : public CppUnit::TestSuite
243{
244public:
245    ArchiveTestSuite(std::string name);
246
247protected:
248    virtual ArchiveTestSuite *makeSuite();
249
250    virtual CppUnit::Test *makeTest(std::string descr,
251                                    int options,
252                                    bool genericInterface,
253                                    const wxString& archiver,
254                                    const wxString& unarchiver);
255
256    void AddArchiver(const wxString& cmd) { AddCmd(m_archivers, cmd); }
257    void AddUnArchiver(const wxString &cmd) { AddCmd(m_unarchivers, cmd); }
258    bool IsInPath(const wxString& cmd);
259
260    std::string Description(const wxString& type,
261                            int options,
262                            bool genericInterface = false,
263                            const wxString& archiver = wxEmptyString,
264                            const wxString& unarchiver = wxEmptyString);
265
266private:
267    wxString m_name;
268    wxPathList m_path;
269    wxArrayString m_archivers;
270    wxArrayString m_unarchivers;
271
272    void AddCmd(wxArrayString& cmdlist, const wxString& cmd);
273};
274