X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/9386cb75e34acb49cd9fac945e09cf002f22db2d..ed626c8b55317c1cc28278ff67c8b78e79303ff6:/tests/archive/archivetest.cpp diff --git a/tests/archive/archivetest.cpp b/tests/archive/archivetest.cpp index 476513e4f4..941b07d002 100644 --- a/tests/archive/archivetest.cpp +++ b/tests/archive/archivetest.cpp @@ -7,7 +7,7 @@ // Licence: wxWindows licence /////////////////////////////////////////////////////////////////////////////// -#include "wx/wxprec.h" +#include "testprec.h" #ifdef __BORLANDC__ # pragma hdrstop @@ -17,26 +17,32 @@ # 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 #include +#include #include +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 @@ -56,82 +62,16 @@ #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; } - wxFileOffset GetLength() 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; @@ -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(); - 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; - 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; @@ -355,16 +253,28 @@ 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 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 TestEntries; - TestEntries m_testEntries; // test data - std::auto_ptr 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 -ArchiveTestCase::ArchiveTestCase(const wxString& name, - int id, - ClassFactoryT *factory, - int options, - const wxString& archiver, - const wxString& unarchiver) - : CppUnit::TestCase(std::string(name.mb_str())), +template +ArchiveTestCase::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 -ArchiveTestCase::~ArchiveTestCase() +template +ArchiveTestCase::~ArchiveTestCase() { TestEntries::iterator it; for (it = m_testEntries.begin(); it != m_testEntries.end(); ++it) delete it->second; } -template -void ArchiveTestCase::runTest() +template +void ArchiveTestCase::runTest() { TestOutputStream out(m_options); @@ -640,7 +477,7 @@ void ArchiveTestCase::runTest() // check archive could be created 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::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 -void ArchiveTestCase::CreateTestData() +template +void ArchiveTestCase::CreateTestData() { Add("text/"); Add("text/empty", ""); @@ -692,10 +529,10 @@ void ArchiveTestCase::CreateTestData() Add("empty/"); } -template -TestEntry& ArchiveTestCase::Add(const char *name, - const char *data, - int len /*=-1*/) +template +TestEntry& ArchiveTestCase::Add(const char *name, + const char *data, + int len /*=-1*/) { if (len == -1) len = strlen(data); @@ -706,23 +543,23 @@ TestEntry& ArchiveTestCase::Add(const char *name, return *entry; } -template -TestEntry& ArchiveTestCase::Add(const char *name, - int len /*=0*/, - int value /*=EOF*/) +template +TestEntry& ArchiveTestCase::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 -void ArchiveTestCase::CreateArchive(wxOutputStream& out) +template +void ArchiveTestCase::CreateArchive(wxOutputStream& out) { - std::auto_ptr arc(m_factory->NewStream(out)); + auto_ptr arc(m_factory->NewStream(out)); TestEntries::iterator it; OnCreateArchive(*arc); @@ -745,12 +582,12 @@ void ArchiveTestCase::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 entry(m_factory->NewEntry()); + auto_ptr entry(m_factory->NewEntry()); entry->SetName(name, wxPATH_UNIX); if (setIsDir) entry->SetIsDir(); @@ -772,7 +609,7 @@ void ArchiveTestCase::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::CreateArchive(wxOutputStream& out) // Create an archive using an external archive program // -template -void ArchiveTestCase::CreateArchive(wxOutputStream& out, - const wxString& archiver) +template +void ArchiveTestCase::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::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::CreateArchive(wxOutputStream& out, // Do a standard set of modification on an archive, delete an entry, // rename an entry and add an entry // -template -void ArchiveTestCase::ModifyArchive(wxInputStream& in, - wxOutputStream& out) +template +void ArchiveTestCase::ModifyArchive(wxInputStream& in, + wxOutputStream& out) { - std::auto_ptr arcIn(m_factory->NewStream(in)); - std::auto_ptr arcOut(m_factory->NewStream(out)); - std::auto_ptr entry; + auto_ptr arcIn(m_factory->NewStream(in)); + auto_ptr 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::ModifyArchive(wxInputStream& in, arcOut->CopyArchiveMetaData(*arcIn); - while (entry.reset(arcIn->GetNextEntry()), entry.get() != NULL) { + while ((pEntry = arcIn->GetNextEntry()) != NULL) { + auto_ptr 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::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 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::ModifyArchive(wxInputStream& in, // Extract an archive using the wx archive classes // -template -void ArchiveTestCase::ExtractArchive(wxInputStream& in) +template +void ArchiveTestCase::ExtractArchive(wxInputStream& in) { typedef Ptr EntryPtr; typedef std::list Entries; typedef typename Entries::iterator EntryIter; - std::auto_ptr arc(m_factory->NewStream(in)); + auto_ptr arc(m_factory->NewStream(in)); int expectedTotal = m_testEntries.size(); EntryPtr entry; Entries entries; @@ -954,8 +792,8 @@ void ArchiveTestCase::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( @@ -1029,9 +867,9 @@ void ArchiveTestCase::ExtractArchive(wxInputStream& in) // Extract an archive using an external unarchive program // -template -void ArchiveTestCase::ExtractArchive(wxInputStream& in, - const wxString& unarchiver) +template +void ArchiveTestCase::ExtractArchive(wxInputStream& in, + const wxString& unarchiver) { // for an external unarchiver, unarchive to a tempdir TempDir tmpdir; @@ -1039,10 +877,10 @@ void ArchiveTestCase::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::ExtractArchive(wxInputStream& in, // Verifies the files produced by an external unarchiver are as expected // -template -void ArchiveTestCase::VerifyDir(wxString& path, size_t rootlen /*=0*/) +template +void ArchiveTestCase::VerifyDir(wxString& path, + size_t rootlen /*=0*/) { wxDir dir; path += wxFileName::GetPathSeparator(); @@ -1092,8 +931,8 @@ void ArchiveTestCase::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( @@ -1103,7 +942,7 @@ void ArchiveTestCase::VerifyDir(wxString& path, size_t rootlen /*=0*/) const TestEntry& testEntry = *it->second; -#ifndef __WXMSW__ +#if 0 //ndef __WXMSW__ CPPUNIT_ASSERT_MESSAGE("timestamp check" + error_context, testEntry.GetDateTime() == wxFileName(path).GetModificationTime()); @@ -1113,7 +952,7 @@ void ArchiveTestCase::VerifyDir(wxString& path, size_t rootlen /*=0*/) CPPUNIT_ASSERT_MESSAGE( "entry not found in archive" + error_entry, in.Ok()); - size_t size = in.GetLength(); + size_t size = (size_t)in.GetLength(); wxCharBuffer buf(size); CPPUNIT_ASSERT_MESSAGE("Read" + error_context, in.Read(buf.data(), size).LastRead() == size); @@ -1135,13 +974,13 @@ void ArchiveTestCase::VerifyDir(wxString& path, size_t rootlen /*=0*/) // test the simple iterators that give away ownership of an entry // -template -void ArchiveTestCase::TestIterator(wxInputStream& in) +template +void ArchiveTestCase::TestIterator(wxInputStream& in) { typedef std::list ArchiveCatalog; typedef typename ArchiveCatalog::iterator CatalogIter; - std::auto_ptr arc(m_factory->NewStream(in)); + auto_ptr arc(m_factory->NewStream(in)); size_t count = 0; #ifdef WXARC_MEMBER_TEMPLATES @@ -1153,7 +992,7 @@ void ArchiveTestCase::TestIterator(wxInputStream& in) #endif for (CatalogIter it = cat.begin(); it != cat.end(); ++it) { - std::auto_ptr entry(*it); + auto_ptr entry(*it); count += m_testEntries.count(entry->GetName(wxPATH_UNIX)); } @@ -1164,13 +1003,13 @@ void ArchiveTestCase::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 -void ArchiveTestCase::TestPairIterator(wxInputStream& in) +template +void ArchiveTestCase::TestPairIterator(wxInputStream& in) { typedef std::map ArchiveCatalog; typedef typename ArchiveCatalog::iterator CatalogIter; - std::auto_ptr arc(m_factory->NewStream(in)); + auto_ptr arc(m_factory->NewStream(in)); size_t count = 0; #ifdef WXARC_MEMBER_TEMPLATES @@ -1178,11 +1017,11 @@ void ArchiveTestCase::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 entry(it->second); + auto_ptr entry(it->second); count += m_testEntries.count(entry->GetName(wxPATH_UNIX)); } @@ -1192,14 +1031,14 @@ void ArchiveTestCase::TestPairIterator(wxInputStream& in) // simple iterators using smart pointers, no need to worry about ownership // -template -void ArchiveTestCase::TestSmartIterator(wxInputStream& in) +template +void ArchiveTestCase::TestSmartIterator(wxInputStream& in) { typedef std::list > ArchiveCatalog; typedef typename ArchiveCatalog::iterator CatalogIter; typedef wxArchiveIterator > Iter; - std::auto_ptr arc(m_factory->NewStream(in)); + auto_ptr arc(m_factory->NewStream(in)); #ifdef WXARC_MEMBER_TEMPLATES ArchiveCatalog cat((Iter)*arc, Iter()); @@ -1217,34 +1056,40 @@ void ArchiveTestCase::TestSmartIterator(wxInputStream& in) // pair iterator using smart pointers // -template -void ArchiveTestCase::TestSmartPairIterator(wxInputStream& in) +template +void ArchiveTestCase::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, so this iterator can't be made to work. + (void)in; +#else typedef std::map > ArchiveCatalog; typedef typename ArchiveCatalog::iterator CatalogIter; typedef wxArchiveIterator > > PairIter; - std::auto_ptr arc(m_factory->NewStream(in)); + auto_ptr 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 -void ArchiveTestCase::ReadSimultaneous(TestInputStream& in) +template +void ArchiveTestCase::ReadSimultaneous(TestInputStream& in) { typedef std::map > ArchiveCatalog; typedef wxArchiveIterator::ReadSimultaneous(TestInputStream& in) // create two archive input streams TestInputStream in2(in); - std::auto_ptr arc(m_factory->NewStream(in)); - std::auto_ptr arc2(m_factory->NewStream(in2)); + auto_ptr arc(m_factory->NewStream(in)); + auto_ptr arc2(m_factory->NewStream(in2)); // load the catalog #ifdef WXARC_MEMBER_TEMPLATES @@ -1261,7 +1106,7 @@ void ArchiveTestCase::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 @@ -1316,8 +1161,8 @@ public: void OnEntryUpdated(EntryT& WXUNUSED(entry)) { } }; -template -void ArchiveTestCase::OnSetNotifier(EntryT& entry) +template +void ArchiveTestCase::OnSetNotifier(EntryT& entry) { static ArchiveNotifier notifier; entry.SetNotifier(notifier); @@ -1325,210 +1170,114 @@ void ArchiveTestCase::OnSetNotifier(EntryT& entry) /////////////////////////////////////////////////////////////////////////////// -// ArchiveTestCase 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 +class CorruptionTestCase : public CppUnit::TestCase { public: - ZipTestCase(const wxString& name, - int id, - int options, - const wxString& archiver = wxEmptyString, - const wxString& unarchiver = wxEmptyString) - : - ArchiveTestCase(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 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 + for (int 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 (int 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 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 arc(m_factory->NewStream(in)); + auto_ptr entry(arc->GetNextEntry()); + + while (entry.get() != NULL) { + wxString name = entry->GetName(); + char buf[1024]; + + while (arc->IsOk()) + arc->Read(buf, sizeof(buf)); + + auto_ptr 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 - -class ZipPipeTestCase : public CppUnit::TestCase -{ -public: - ZipPipeTestCase(const wxString& name, int options) : - CppUnit::TestCase(std::string(name.mb_str())), m_options(options) { } +// Make the ids -protected: - void runTest(); - int m_options; -}; +int TestId::m_seed = 6219; -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 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 - -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); -}; +// Suite base -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 @@ -1536,8 +1285,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); } @@ -1556,73 +1303,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( - 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) @@ -1636,13 +1393,18 @@ 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; + +#if wxUSE_ZIPSTREAM +#include "wx/zipstrm.h" +template class ArchiveTestCase; +#endif -#endif // wxUSE_STREAMS +#endif // wxUSE_STREAMS && wxUSE_ARCHIVE_STREAMS