X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/95662a8379c192db4d8b4fcd9d404506ea302393..3c3ead1d1513a5eb79091a604f4e42b45d1bdf5d:/tests/archive/archivetest.cpp?ds=inline diff --git a/tests/archive/archivetest.cpp b/tests/archive/archivetest.cpp index 5395d6c2f8..aa843b4e8c 100644 --- a/tests/archive/archivetest.cpp +++ b/tests/archive/archivetest.cpp @@ -17,19 +17,15 @@ # include "wx/wx.h" #endif -#if wxUSE_STREAMS +#if wxUSE_STREAMS && wxUSE_ARCHIVE_STREAMS -#define WX_TEST_ARCHIVE_ITERATOR - -// This sample uses some advanced typedef syntax that messes -// up MSVC 6 - turn off its warning about it -#if defined _MSC_VER +// 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 #include @@ -46,7 +42,7 @@ using std::auto_ptr; (__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 @@ -66,82 +62,16 @@ using std::auto_ptr; #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 [] (char*) 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; @@ -152,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) @@ -256,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; @@ -282,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 [] (char*) 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; @@ -329,15 +216,16 @@ void TestInputStream::Rewind() m_wbacksize = 0; m_wbackcur = 0; } + + Reset(); } void TestInputStream::SetData(TestOutputStream& out) { - delete [] (char*) m_data; + delete [] m_data; m_options = out.GetOptions(); out.GetData(m_data, m_size); Rewind(); - Reset(); } wxFileOffset TestInputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode) @@ -348,7 +236,7 @@ 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 = (size_t)pos; return m_pos; @@ -365,16 +253,30 @@ 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; } @@ -433,8 +335,8 @@ private: TempDir::TempDir() { - wxString tmp = wxFileName::CreateTempFileName(_T("arctest-")); - if (tmp != wxEmptyString) { + wxString tmp = wxFileName::CreateTempFileName(wxT("arctest-")); + if (!tmp.empty()) { wxRemoveFile(tmp); m_original = wxGetCwd(); CPPUNIT_ASSERT(wxMkdir(tmp, 0700)); @@ -445,7 +347,7 @@ TempDir::TempDir() TempDir::~TempDir() { - if (m_tmp != wxEmptyString) { + if (!m_tmp.empty()) { wxSetWorkingDirectory(m_original); RemoveDir(m_tmp); } @@ -454,26 +356,26 @@ TempDir::~TempDir() void TempDir::RemoveDir(wxString& path) { wxCHECK_RET(!m_tmp.empty() && path.substr(0, m_tmp.length()) == m_tmp, - _T("remove '") + path + _T("' fails safety check")); + wxT("remove '") + path + wxT("' fails safety check")); const wxChar *files[] = { - _T("text/empty"), - _T("text/small"), - _T("bin/bin1000"), - _T("bin/bin4095"), - _T("bin/bin4096"), - _T("bin/bin4097"), - _T("bin/bin16384"), - _T("zero/zero5"), - _T("zero/zero1024"), - _T("zero/zero32768"), - _T("zero/zero16385"), - _T("zero/newname"), - _T("newfile"), + wxT("text/empty"), + wxT("text/small"), + wxT("bin/bin1000"), + wxT("bin/bin4095"), + wxT("bin/bin4096"), + wxT("bin/bin4097"), + wxT("bin/bin16384"), + wxT("zero/zero5"), + wxT("zero/zero1024"), + wxT("zero/zero32768"), + wxT("zero/zero16385"), + wxT("zero/newname"), + wxT("newfile"), }; const wxChar *dirs[] = { - _T("text/"), _T("bin/"), _T("zero/"), _T("empty/") + wxT("text/"), wxT("bin/"), wxT("zero/"), wxT("empty/") }; wxString tmp = m_tmp + wxFileName::GetPathSeparator(); @@ -486,7 +388,9 @@ void TempDir::RemoveDir(wxString& path) wxRmdir(tmp + wxFileName(dirs[i], wxPATH_UNIX).GetFullPath()); if (!wxRmdir(m_tmp)) - wxLogSysError(_T("can't remove temporary dir '%s'"), m_tmp.c_str()); + { + wxLogSysError(wxT("can't remove temporary dir '%s'"), m_tmp.c_str()); + } } @@ -511,143 +415,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(string name, - int id, - wxArchiveClassFactory *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 - 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 -// Constructor -// The only way I could get this to compile on VC++ 5.0 was to pass 'factory' -// as a wxArchiveFactory* then cast it, even then only with some ifdefing. -// -template -ArchiveTestCase::ArchiveTestCase( +template +ArchiveTestCase::ArchiveTestCase( string name, - int id, - wxArchiveClassFactory *factory, + ClassFactoryT *factory, int options, const wxString& archiver, const wxString& unarchiver) : - CppUnit::TestCase(name), -#if defined _MSC_VER && _MSC_VER < 1300 - m_factory(dynamic_cast(factory)), -#else - m_factory(dynamic_cast(factory)), -#endif + 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); @@ -661,7 +481,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(); @@ -684,13 +504,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", ""); @@ -713,10 +533,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); @@ -727,21 +547,21 @@ 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) { auto_ptr arc(m_factory->NewStream(out)); TestEntries::iterator it; @@ -760,13 +580,13 @@ void ArchiveTestCase::CreateArchive(wxOutputStream& out) // It should be possible to create a directory entry just by supplying // a name that looks like a directory, or alternatively any old name // can be identified as a directory using SetIsDir or PutNextDirEntry - bool setIsDir = name.Last() == _T('/') && (choices & 1); + bool setIsDir = name.Last() == wxT('/') && (choices & 1); if (setIsDir) name.erase(name.length() - 1); // provide some context for the error message so that we know which // iteration of the loop we were on - string error_entry((_T(" '") + name + _T("'")).mb_str()); + string error_entry((wxT(" '") + name + wxT("'")).mb_str()); string error_context(" failed for entry" + error_entry); if ((choices & 2) || testEntry.IsText()) { @@ -793,7 +613,7 @@ void ArchiveTestCase::CreateArchive(wxOutputStream& out) testEntry.GetLength())); } - if (name.Last() != _T('/')) { + if (it->first.Last() != wxT('/')) { // for non-dirs write the data arc->Write(testEntry.GetData(), testEntry.GetSize()); CPPUNIT_ASSERT_MESSAGE("LastWrite check" + error_context, @@ -814,9 +634,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 @@ -829,7 +649,7 @@ void ArchiveTestCase::CreateArchive(wxOutputStream& out, TestEntry& entry = *i->second; if (fn.IsDir()) { - fn.Mkdir(0777, wxPATH_MKDIR_FULL); + wxFileName::Mkdir(fn.GetPath(), 0777, wxPATH_MKDIR_FULL); } else { wxFileName::Mkdir(fn.GetPath(), 0777, wxPATH_MKDIR_FULL); wxFFileOutputStream fileout(fn.GetFullPath()); @@ -851,8 +671,8 @@ void ArchiveTestCase::CreateArchive(wxOutputStream& out, if ((m_options & PipeOut) == 0) { wxFileName fn(tmpdir.GetName()); - fn.SetExt(_T("arc")); - wxString tmparc = fn.GetFullPath(); + fn.SetExt(wxT("arc")); + 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()); @@ -869,7 +689,7 @@ void ArchiveTestCase::CreateArchive(wxOutputStream& out, else { // for the non-seekable test, have the archiver output to "-" // and read the archive via a pipe - PFileInputStream in(wxString::Format(archiver, _T("-"))); + PFileInputStream in(wxString::Format(archiver, wxT("-"))); if (in.Ok()) out.Write(in); } @@ -878,34 +698,30 @@ 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) { 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"); - const wxString renameTo = _T("zero/newname"); - const wxString newName = _T("newfile"); + const wxString deleteName = wxT("bin/bin1000"); + const wxString renameFrom = wxT("zero/zero1024"); + const wxString renameTo = wxT("zero/newname"); + const wxString newName = wxT("newfile"); const char *newData = "New file added as a test\n"; arcOut->CopyArchiveMetaData(*arcIn); - auto_ptr* pEntry; - - for (pEntry = new auto_ptr(arcIn->GetNextEntry()) ; - pEntry->get() != NULL ; - delete pEntry, pEntry = new auto_ptr(arcIn->GetNextEntry())) - { - OnSetNotifier(**pEntry); - wxString name = (*pEntry)->GetName(wxPATH_UNIX); + 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 - string error_entry((_T(" '") + name + _T("'")).mb_str()); + string error_entry((wxT(" '") + name + wxT("'")).mb_str()); string error_context(" failed for entry" + error_entry); if (name == deleteName) { @@ -919,7 +735,7 @@ void ArchiveTestCase::ModifyArchive(wxInputStream& in, } else { if (name == renameFrom) { - (*pEntry)->SetName(renameTo); + entry->SetName(renameTo); TestEntries::iterator it = m_testEntries.find(renameFrom); CPPUNIT_ASSERT_MESSAGE( "rename failed (already renamed?) for" + error_entry, @@ -930,12 +746,10 @@ void ArchiveTestCase::ModifyArchive(wxInputStream& in, } CPPUNIT_ASSERT_MESSAGE("CopyEntry" + error_context, - arcOut->CopyEntry(pEntry->release(), *arcIn)); + arcOut->CopyEntry(entry.release(), *arcIn)); } } - delete pEntry; - // check that the deletion and rename were done CPPUNIT_ASSERT(m_testEntries.count(deleteName) == 0); CPPUNIT_ASSERT(m_testEntries.count(renameFrom) == 0); @@ -962,8 +776,8 @@ 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; @@ -982,7 +796,7 @@ void ArchiveTestCase::ExtractArchive(wxInputStream& in) // provide some context for the error message so that we know which // iteration of the loop we were on - string error_entry((_T(" '") + name + _T("'")).mb_str()); + string error_entry((wxT(" '") + name + wxT("'")).mb_str()); string error_context(" failed for entry" + error_entry); TestEntries::iterator it = m_testEntries.find(name); @@ -992,10 +806,14 @@ void ArchiveTestCase::ExtractArchive(wxInputStream& in) const TestEntry& testEntry = *it->second; +#ifndef __WXMSW__ + // On Windows some archivers compensate for Windows DST handling, but + // other don't, so disable the test for now. wxDateTime dt = testEntry.GetDateTime(); if (dt.IsValid()) CPPUNIT_ASSERT_MESSAGE("timestamp check" + error_context, dt == entry->GetDateTime()); +#endif // non-seekable entries are allowed to have GetSize == wxInvalidOffset // until the end of the entry's data has been read past @@ -1006,7 +824,7 @@ void ArchiveTestCase::ExtractArchive(wxInputStream& in) "arc->GetLength() == entry->GetSize()" + error_context, arc->GetLength() == entry->GetSize()); - if (name.Last() != _T('/')) + if (name.Last() != wxT('/')) { CPPUNIT_ASSERT_MESSAGE("!IsDir" + error_context, !entry->IsDir()); @@ -1057,20 +875,20 @@ 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; if ((m_options & PipeIn) == 0) { wxFileName fn(tmpdir.GetName()); - fn.SetExt(_T("arc")); - wxString tmparc = fn.GetFullPath(); - + fn.SetExt(wxT("arc")); + 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 { @@ -1086,7 +904,7 @@ void ArchiveTestCase::ExtractArchive(wxInputStream& in, else { // for the non-seekable test, have the archiver extract "-" and // feed it the archive via a pipe - PFileOutputStream out(wxString::Format(unarchiver, _T("-"))); + PFileOutputStream out(wxString::Format(unarchiver, wxT("-"))); if (out.Ok()) out.Write(in); } @@ -1097,8 +915,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(); @@ -1116,11 +935,11 @@ void ArchiveTestCase::VerifyDir(wxString& path, size_t rootlen /*=0*/) bool isDir = wxDirExists(path); if (isDir) - name += _T("/"); + name += wxT("/"); // provide some context for the error message so that we know which // iteration of the loop we were on - string error_entry((_T(" '") + name + _T("'")).mb_str()); + string error_entry((wxT(" '") + name + wxT("'")).mb_str()); string error_context(" failed for entry" + error_entry); TestEntries::iterator it = m_testEntries.find(name); @@ -1131,7 +950,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()); @@ -1141,7 +960,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); @@ -1163,8 +982,8 @@ 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; @@ -1192,8 +1011,8 @@ 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; @@ -1220,8 +1039,8 @@ 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; @@ -1245,9 +1064,14 @@ 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::TestSmartPairIterator(wxInputStream& in) 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) #endif // the names of two entries to read - const wxChar *name = _T("text/small"); - const wxChar *name2 = _T("bin/bin1000"); + const wxChar *name = wxT("text/small"); + const wxChar *name2 = wxT("bin/bin1000"); // open them typename ArchiveCatalog::iterator j; @@ -1344,8 +1169,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); @@ -1353,211 +1178,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(string 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 + int pos; + for (pos = 0; pos < len; pos++) { + char n = in[pos]; + in[pos] = ~n; + ExtractArchive(in); + in.Rewind(); + in[pos] = n; } - m_count++; -} + // 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; + } -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 - wxString name = _T(" '") + entry.GetName() + _T("'"); - string error_entry(name.mb_str()); - 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()); - - 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(wxT("dir")); + arc->PutNextEntry(wxT("file")); + arc->Write(wxT("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) { + char buf[1024]; -/////////////////////////////////////////////////////////////////////////////// -// '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 + while (arc->IsOk()) + arc->Read(buf, sizeof(buf)); -class ZipPipeTestCase : public CppUnit::TestCase -{ -public: - ZipPipeTestCase(string name, int options) : - CppUnit::TestCase(name), m_options(options) { } - -protected: - void runTest(); - int m_options; -}; - -void ZipPipeTestCase::runTest() -{ - 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); + auto_ptr next(arc->GetNextEntry()); + entry = next; } +} - TestInputStream in(out); - wxZipInputStream zip(in); - - 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(); +/////////////////////////////////////////////////////////////////////////////// +// Make the ids - while (len > 0 && buf[len - 1] <= 32) - --len; - buf[len] = 0; +int TestId::m_seed = 6219; - CPPUNIT_ASSERT(zip.Eof()); - CPPUNIT_ASSERT(wxString(buf, *wxConvCurrent) == testdata); +// static +string TestId::MakeId() +{ + m_seed = (m_seed * 171) % 30269; + return string(wxString::Format(wxT("%-6d"), m_seed).mb_str()); } /////////////////////////////////////////////////////////////////////////////// -// The suite +// Suite base -class ArchiveTestSuite : public CppUnit::TestSuite +ArchiveTestSuite::ArchiveTestSuite(string name) + : CppUnit::TestSuite("archive/" + name), + m_name(name.c_str(), *wxConvCurrent) { -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); - - string 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) -{ - m_path.AddEnvList(_T("PATH")); + m_name = wxT("wx") + m_name.Left(1).Upper() + m_name.Mid(1).Lower(); + m_path.AddEnvList(wxT("PATH")); + m_archivers.push_back(wxT("")); + m_unarchivers.push_back(wxT("")); } // add the command for an external archiver to the list, testing for it in @@ -1565,17 +1293,15 @@ ArchiveTestSuite::ArchiveTestSuite() // void ArchiveTestSuite::AddCmd(wxArrayString& cmdlist, const wxString& cmd) { - if (cmdlist.empty()) - cmdlist.push_back(_T("")); if (IsInPath(cmd)) cmdlist.push_back(cmd); } bool ArchiveTestSuite::IsInPath(const wxString& cmd) { - wxString c = cmd.BeforeFirst(_T(' ')); + wxString c = cmd.BeforeFirst(wxT(' ')); #ifdef __WXMSW__ - c += _T(".exe"); + c += wxT(".exe"); #endif return !m_path.FindValidPath(c).empty(); } @@ -1585,52 +1311,59 @@ 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 - string 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) { - string 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 + wxT("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 // string ArchiveTestSuite::Description(const wxString& type, @@ -1640,38 +1373,51 @@ string ArchiveTestSuite::Description(const wxString& type, const wxString& unarchiver) { wxString descr; - descr << m_id << _T(" "); - + if (genericInterface) - descr << _T("wxArchive (") << type << _T(")"); + descr << wxT("wxArchive (") << type << wxT(")"); 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 ? wxT("-") : wxT("file"); + descr << wxT(" (") << wxString::Format(archiver, fn) << wxT(")"); + } + if (!unarchiver.empty()) { + const wxChar *fn = (options & PipeIn) != 0 ? wxT("-") : wxT("file"); + descr << wxT(" (") << wxString::Format(unarchiver, fn) << wxT(")"); + } + wxString optstr; if ((options & PipeIn) != 0) - optstr += _T("|PipeIn"); + optstr += wxT("|PipeIn"); if ((options & PipeOut) != 0) - optstr += _T("|PipeOut"); + optstr += wxT("|PipeOut"); if ((options & Stub) != 0) - optstr += _T("|Stub"); + optstr += wxT("|Stub"); if (!optstr.empty()) - optstr = _T(" (") + optstr.substr(1) + _T(")"); + optstr = wxT(" (") + optstr.substr(1) + wxT(")"); descr << optstr; - return (const char*)descr.mb_str(); + 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 + +#if wxUSE_TARSTREAM +#include "wx/tarstrm.h" +template class ArchiveTestCase; +#endif -#endif // wxUSE_STREAMS +#endif // wxUSE_STREAMS && wxUSE_ARCHIVE_STREAMS