// 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;
// 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)
}
if (pos < 0 || pos > SEEK_LIMIT)
return wxInvalidOffset;
- m_pos = pos;
+ m_pos = (size_t)pos;
return m_pos;
}
return wxInvalidOffset;
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)
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;
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;
m_wbacksize = 0;
m_wbackcur = 0;
}
+
+ Reset();
}
void TestInputStream::SetData(TestOutputStream& out)
m_options = out.GetOptions();
out.GetData(m_data, m_size);
Rewind();
- Reset();
}
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;
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;
}
TempDir::TempDir()
{
wxString tmp = wxFileName::CreateTempFileName(_T("arctest-"));
- if (tmp != wxEmptyString) {
+ if (!tmp.empty()) {
wxRemoveFile(tmp);
m_original = wxGetCwd();
CPPUNIT_ASSERT(wxMkdir(tmp, 0700));
TempDir::~TempDir()
{
- if (m_tmp != wxEmptyString) {
+ if (!m_tmp.empty()) {
wxSetWorkingDirectory(m_original);
RemoveDir(m_tmp);
}
# 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);
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();
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", "");
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);
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);
// 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();
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,
// 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
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());
// 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");
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);
// 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
// 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;
// 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(
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('/'))
{
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());
// 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;
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
{
// 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();
// 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(
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());
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);
// 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
#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));
}
// 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
#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));
}
// 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());
// 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,
// 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
#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
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);
///////////////////////////////////////////////////////////////////////////////
-// 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
//
void ArchiveTestSuite::AddCmd(wxArrayString& cmdlist, const wxString& cmd)
{
- if (cmdlist.empty())
- cmdlist.push_back(_T(""));
if (IsInPath(cmd))
cmdlist.push_back(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)
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