2004-11-10 18:58:38 -05:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Name: tests/archive/archive.cpp
|
|
|
|
// Purpose: Test the archive classes
|
|
|
|
// Author: Mike Wetherell
|
|
|
|
// Copyright: (c) 2004 Mike Wetherell
|
|
|
|
// Licence: wxWindows licence
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2004-11-22 00:00:19 -05:00
|
|
|
#include "testprec.h"
|
2004-11-10 18:58:38 -05:00
|
|
|
|
|
|
|
#ifndef WX_PRECOMP
|
|
|
|
# include "wx/wx.h"
|
|
|
|
#endif
|
|
|
|
|
2005-02-12 16:40:48 -05:00
|
|
|
#if wxUSE_STREAMS && wxUSE_ARCHIVE_STREAMS
|
2004-11-10 18:58:38 -05:00
|
|
|
|
2005-02-10 09:06:08 -05:00
|
|
|
#include "archivetest.h"
|
2004-11-10 18:58:38 -05:00
|
|
|
#include "wx/dir.h"
|
|
|
|
#include <string>
|
|
|
|
#include <list>
|
2004-11-23 08:49:43 -05:00
|
|
|
#include <map>
|
2004-11-10 18:58:38 -05:00
|
|
|
#include <sys/stat.h>
|
|
|
|
|
2004-11-23 08:49:43 -05:00
|
|
|
using std::string;
|
|
|
|
|
|
|
|
|
2004-11-10 18:58:38 -05:00
|
|
|
// Check whether member templates can be used
|
|
|
|
//
|
2020-10-19 13:38:53 -04:00
|
|
|
#if defined __GNUC__
|
2004-11-10 18:58:38 -05:00
|
|
|
# define WXARC_MEMBER_TEMPLATES
|
|
|
|
#endif
|
2005-10-15 15:00:12 -04:00
|
|
|
#if defined _MSC_VER && _MSC_VER >= 1310 && !defined __WIN64__
|
2004-11-10 18:58:38 -05:00
|
|
|
# define WXARC_MEMBER_TEMPLATES
|
|
|
|
#endif
|
|
|
|
#if defined __HP_aCC && __HP_aCC > 33300
|
|
|
|
# define WXARC_MEMBER_TEMPLATES
|
|
|
|
#endif
|
|
|
|
#if defined __SUNPRO_CC && __SUNPRO_CC > 0x500
|
|
|
|
# define WXARC_MEMBER_TEMPLATES
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// A class to hold a test entry
|
|
|
|
|
|
|
|
TestEntry::TestEntry(const wxDateTime& dt, int len, const char *data)
|
|
|
|
: m_dt(dt),
|
|
|
|
m_len(len),
|
|
|
|
m_isText(len > 0)
|
|
|
|
{
|
2004-11-25 15:37:44 -05:00
|
|
|
m_data = new char[len];
|
|
|
|
memcpy(m_data, data, len);
|
2004-11-10 18:58:38 -05:00
|
|
|
|
|
|
|
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.
|
|
|
|
|
2005-02-10 09:06:08 -05:00
|
|
|
const size_t STUB_SIZE = 2048;
|
|
|
|
const size_t INITIAL_SIZE = 0x18000;
|
|
|
|
const wxFileOffset SEEK_LIMIT = 0x100000;
|
2004-11-10 18:58:38 -05:00
|
|
|
|
|
|
|
TestOutputStream::TestOutputStream(int options)
|
|
|
|
: m_options(options)
|
|
|
|
{
|
|
|
|
Init();
|
|
|
|
}
|
|
|
|
|
|
|
|
void TestOutputStream::Init()
|
|
|
|
{
|
|
|
|
m_data = NULL;
|
|
|
|
m_size = 0;
|
|
|
|
m_capacity = 0;
|
|
|
|
m_pos = 0;
|
|
|
|
|
|
|
|
if (m_options & Stub) {
|
|
|
|
wxCharBuffer buf(STUB_SIZE);
|
|
|
|
memset(buf.data(), 0, STUB_SIZE);
|
|
|
|
Write(buf, STUB_SIZE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
wxFileOffset TestOutputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode)
|
|
|
|
{
|
|
|
|
if ((m_options & PipeOut) == 0) {
|
|
|
|
switch (mode) {
|
|
|
|
case wxFromStart: break;
|
|
|
|
case wxFromCurrent: pos += m_pos; break;
|
|
|
|
case wxFromEnd: pos += m_size; break;
|
|
|
|
}
|
|
|
|
if (pos < 0 || pos > SEEK_LIMIT)
|
|
|
|
return wxInvalidOffset;
|
2004-11-23 08:49:43 -05:00
|
|
|
m_pos = (size_t)pos;
|
2004-11-10 18:58:38 -05:00
|
|
|
return m_pos;
|
|
|
|
}
|
|
|
|
return wxInvalidOffset;
|
|
|
|
}
|
|
|
|
|
|
|
|
wxFileOffset TestOutputStream::OnSysTell() const
|
|
|
|
{
|
2004-11-11 14:10:35 -05:00
|
|
|
return (m_options & PipeOut) == 0 ? (wxFileOffset)m_pos : wxInvalidOffset;
|
2004-11-10 18:58:38 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
size_t TestOutputStream::OnSysWrite(const void *buffer, size_t size)
|
|
|
|
{
|
|
|
|
if (!IsOk() || !size)
|
|
|
|
return 0;
|
|
|
|
m_lasterror = wxSTREAM_WRITE_ERROR;
|
|
|
|
|
|
|
|
size_t newsize = m_pos + size;
|
|
|
|
wxCHECK(newsize > m_pos, 0);
|
|
|
|
|
|
|
|
if (m_capacity < newsize) {
|
2005-02-10 09:06:08 -05:00
|
|
|
size_t capacity = m_capacity ? m_capacity : INITIAL_SIZE;
|
2004-11-10 18:58:38 -05:00
|
|
|
|
|
|
|
while (capacity < newsize) {
|
|
|
|
capacity <<= 1;
|
|
|
|
wxCHECK(capacity > m_capacity, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
char *buf = new char[capacity];
|
|
|
|
if (m_data)
|
|
|
|
memcpy(buf, m_data, m_capacity);
|
|
|
|
delete [] m_data;
|
|
|
|
m_data = buf;
|
|
|
|
m_capacity = capacity;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(m_data + m_pos, buffer, size);
|
|
|
|
m_pos += size;
|
|
|
|
if (m_pos > m_size)
|
|
|
|
m_size = m_pos;
|
|
|
|
m_lasterror = wxSTREAM_NO_ERROR;
|
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2004-11-25 15:37:44 -05:00
|
|
|
void TestOutputStream::GetData(char*& data, size_t& size)
|
2004-11-10 18:58:38 -05:00
|
|
|
{
|
|
|
|
data = m_data;
|
|
|
|
size = m_size;
|
|
|
|
|
|
|
|
if (m_options & Stub) {
|
|
|
|
char *d = m_data;
|
|
|
|
size += STUB_SIZE;
|
|
|
|
|
|
|
|
if (size > m_capacity) {
|
|
|
|
d = new char[size];
|
|
|
|
memcpy(d + STUB_SIZE, m_data, m_size);
|
|
|
|
delete [] m_data;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
memmove(d + STUB_SIZE, d, m_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(d, 0, STUB_SIZE);
|
|
|
|
data = d;
|
|
|
|
}
|
|
|
|
|
|
|
|
Init();
|
|
|
|
Reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-02-10 09:06:08 -05:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// TestOutputStream and TestInputStream are memory streams which can be
|
|
|
|
// seekable or non-seekable.
|
2004-11-10 18:58:38 -05:00
|
|
|
|
|
|
|
TestInputStream::TestInputStream(const TestInputStream& in)
|
2005-01-18 14:50:43 -05:00
|
|
|
: wxInputStream(),
|
|
|
|
m_options(in.m_options),
|
2004-11-10 18:58:38 -05:00
|
|
|
m_pos(in.m_pos),
|
2005-12-18 08:58:55 -05:00
|
|
|
m_size(in.m_size),
|
|
|
|
m_eoftype(in.m_eoftype)
|
2004-11-10 18:58:38 -05:00
|
|
|
{
|
2004-11-25 15:37:44 -05:00
|
|
|
m_data = new char[m_size];
|
|
|
|
memcpy(m_data, in.m_data, m_size);
|
2004-11-10 18:58:38 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void TestInputStream::Rewind()
|
|
|
|
{
|
|
|
|
if ((m_options & Stub) && (m_options & PipeIn))
|
2005-02-10 09:06:08 -05:00
|
|
|
m_pos = STUB_SIZE * 2;
|
2004-11-10 18:58:38 -05:00
|
|
|
else
|
|
|
|
m_pos = 0;
|
|
|
|
|
|
|
|
if (m_wbacksize) {
|
|
|
|
free(m_wback);
|
|
|
|
m_wback = NULL;
|
|
|
|
m_wbacksize = 0;
|
|
|
|
m_wbackcur = 0;
|
|
|
|
}
|
2006-09-24 07:52:53 -04:00
|
|
|
|
|
|
|
Reset();
|
2004-11-10 18:58:38 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void TestInputStream::SetData(TestOutputStream& out)
|
|
|
|
{
|
2004-11-25 15:37:44 -05:00
|
|
|
delete [] m_data;
|
2004-11-10 18:58:38 -05:00
|
|
|
m_options = out.GetOptions();
|
|
|
|
out.GetData(m_data, m_size);
|
|
|
|
Rewind();
|
|
|
|
}
|
|
|
|
|
|
|
|
wxFileOffset TestInputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode)
|
|
|
|
{
|
|
|
|
if ((m_options & PipeIn) == 0) {
|
|
|
|
switch (mode) {
|
|
|
|
case wxFromStart: break;
|
|
|
|
case wxFromCurrent: pos += m_pos; break;
|
|
|
|
case wxFromEnd: pos += m_size; break;
|
|
|
|
}
|
2005-02-10 09:06:08 -05:00
|
|
|
if (pos < 0 || pos > SEEK_LIMIT)
|
2004-11-10 18:58:38 -05:00
|
|
|
return wxInvalidOffset;
|
2004-11-23 08:49:43 -05:00
|
|
|
m_pos = (size_t)pos;
|
2004-11-10 18:58:38 -05:00
|
|
|
return m_pos;
|
|
|
|
}
|
|
|
|
return wxInvalidOffset;
|
|
|
|
}
|
|
|
|
|
|
|
|
wxFileOffset TestInputStream::OnSysTell() const
|
|
|
|
{
|
2004-11-11 14:10:35 -05:00
|
|
|
return (m_options & PipeIn) == 0 ? (wxFileOffset)m_pos : wxInvalidOffset;
|
2004-11-10 18:58:38 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
size_t TestInputStream::OnSysRead(void *buffer, size_t size)
|
|
|
|
{
|
|
|
|
if (!IsOk() || !size)
|
|
|
|
return 0;
|
2005-12-18 08:58:55 -05:00
|
|
|
|
|
|
|
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;
|
2004-11-10 18:58:38 -05:00
|
|
|
}
|
|
|
|
|
2005-12-18 08:58:55 -05:00
|
|
|
if (((m_eoftype & AtLast) != 0 && m_pos >= m_size) || count < size)
|
2008-09-11 10:00:33 -04:00
|
|
|
{
|
2005-12-18 08:58:55 -05:00
|
|
|
if ((m_eoftype & WithError) != 0)
|
|
|
|
m_lasterror = wxSTREAM_READ_ERROR;
|
|
|
|
else
|
|
|
|
m_lasterror = wxSTREAM_EOF;
|
2008-09-11 10:00:33 -04:00
|
|
|
}
|
2005-12-18 08:58:55 -05:00
|
|
|
|
|
|
|
return count;
|
2004-11-10 18:58:38 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// minimal non-intrusive reference counting pointer for testing the iterators
|
|
|
|
|
|
|
|
template <class T> class Ptr
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
explicit Ptr(T* p = NULL) : m_p(p), m_count(new int) { *m_count = 1; }
|
|
|
|
Ptr(const Ptr& sp) : m_p(sp.m_p), m_count(sp.m_count) { ++*m_count; }
|
|
|
|
~Ptr() { Free(); }
|
|
|
|
|
|
|
|
Ptr& operator =(const Ptr& sp) {
|
|
|
|
if (&sp != this) {
|
|
|
|
Free();
|
|
|
|
m_p = sp.m_p;
|
|
|
|
m_count = sp.m_count;
|
|
|
|
++*m_count;
|
|
|
|
}
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
T* get() const { return m_p; }
|
|
|
|
T* operator->() const { return m_p; }
|
|
|
|
T& operator*() const { return *m_p; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
void Free() {
|
|
|
|
if (--*m_count == 0) {
|
|
|
|
delete m_p;
|
|
|
|
delete m_count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
T *m_p;
|
|
|
|
int *m_count;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Clean-up for temp directory
|
|
|
|
|
|
|
|
class TempDir
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
TempDir();
|
|
|
|
~TempDir();
|
|
|
|
wxString GetName() const { return m_tmp; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
void RemoveDir(wxString& path);
|
|
|
|
wxString m_tmp;
|
|
|
|
wxString m_original;
|
|
|
|
};
|
|
|
|
|
|
|
|
TempDir::TempDir()
|
|
|
|
{
|
2009-07-23 16:30:22 -04:00
|
|
|
wxString tmp = wxFileName::CreateTempFileName(wxT("arctest-"));
|
2005-03-24 15:01:55 -05:00
|
|
|
if (!tmp.empty()) {
|
2004-11-10 18:58:38 -05:00
|
|
|
wxRemoveFile(tmp);
|
|
|
|
m_original = wxGetCwd();
|
|
|
|
CPPUNIT_ASSERT(wxMkdir(tmp, 0700));
|
|
|
|
m_tmp = tmp;
|
|
|
|
CPPUNIT_ASSERT(wxSetWorkingDirectory(tmp));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TempDir::~TempDir()
|
|
|
|
{
|
2005-03-24 15:01:55 -05:00
|
|
|
if (!m_tmp.empty()) {
|
2004-11-10 18:58:38 -05:00
|
|
|
wxSetWorkingDirectory(m_original);
|
|
|
|
RemoveDir(m_tmp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void TempDir::RemoveDir(wxString& path)
|
|
|
|
{
|
|
|
|
wxCHECK_RET(!m_tmp.empty() && path.substr(0, m_tmp.length()) == m_tmp,
|
2009-07-23 16:30:22 -04:00
|
|
|
wxT("remove '") + path + wxT("' fails safety check"));
|
2004-11-10 18:58:38 -05:00
|
|
|
|
|
|
|
const wxChar *files[] = {
|
2009-07-23 16:30:22 -04:00
|
|
|
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"),
|
2004-11-10 18:58:38 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
const wxChar *dirs[] = {
|
2009-07-23 16:30:22 -04:00
|
|
|
wxT("text/"), wxT("bin/"), wxT("zero/"), wxT("empty/")
|
2004-11-10 18:58:38 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
wxString tmp = m_tmp + wxFileName::GetPathSeparator();
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < WXSIZEOF(files); i++)
|
|
|
|
wxRemoveFile(tmp + wxFileName(files[i], wxPATH_UNIX).GetFullPath());
|
|
|
|
|
|
|
|
for (i = 0; i < WXSIZEOF(dirs); i++)
|
|
|
|
wxRmdir(tmp + wxFileName(dirs[i], wxPATH_UNIX).GetFullPath());
|
|
|
|
|
|
|
|
if (!wxRmdir(m_tmp))
|
2009-07-20 12:47:54 -04:00
|
|
|
{
|
2021-07-04 09:28:55 -04:00
|
|
|
wxLogSysError(wxT("can't remove temporary dir '%s'"), m_tmp);
|
2009-07-20 12:47:54 -04:00
|
|
|
}
|
2004-11-10 18:58:38 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// wxFFile streams for piping to/from an external program
|
|
|
|
|
|
|
|
#if defined __UNIX__ || defined __MINGW32__
|
|
|
|
# define WXARC_popen popen
|
|
|
|
# define WXARC_pclose pclose
|
2020-10-13 12:32:49 -04:00
|
|
|
#elif defined _MSC_VER
|
2004-11-10 18:58:38 -05:00
|
|
|
# define WXARC_popen _popen
|
|
|
|
# define WXARC_pclose _pclose
|
|
|
|
#else
|
|
|
|
# define WXARC_NO_POPEN
|
|
|
|
# define WXARC_popen(cmd, type) NULL
|
|
|
|
# define WXARC_pclose(fp)
|
|
|
|
#endif
|
|
|
|
|
2012-03-04 15:31:42 -05:00
|
|
|
#ifdef __WINDOWS__
|
2004-11-10 18:58:38 -05:00
|
|
|
# define WXARC_b "b"
|
|
|
|
#else
|
|
|
|
# define WXARC_b
|
|
|
|
#endif
|
|
|
|
|
2005-02-10 09:06:08 -05:00
|
|
|
PFileInputStream::PFileInputStream(const wxString& cmd)
|
|
|
|
: wxFFileInputStream(WXARC_popen(cmd.mb_str(), "r" WXARC_b))
|
2004-11-10 18:58:38 -05:00
|
|
|
{
|
2005-02-10 09:06:08 -05:00
|
|
|
}
|
2004-11-10 18:58:38 -05:00
|
|
|
|
2005-02-10 09:06:08 -05:00
|
|
|
PFileInputStream::~PFileInputStream()
|
2004-11-10 18:58:38 -05:00
|
|
|
{
|
2005-02-10 09:06:08 -05:00
|
|
|
WXARC_pclose(m_file->fp()); m_file->Detach();
|
|
|
|
}
|
|
|
|
|
|
|
|
PFileOutputStream::PFileOutputStream(const wxString& cmd)
|
|
|
|
: wxFFileOutputStream(WXARC_popen(cmd.mb_str(), "w" WXARC_b))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
PFileOutputStream::~PFileOutputStream()
|
|
|
|
{
|
|
|
|
WXARC_pclose(m_file->fp()); m_file->Detach();
|
|
|
|
}
|
2004-11-10 18:58:38 -05:00
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// The test case
|
|
|
|
|
2005-02-10 09:06:08 -05:00
|
|
|
template <class ClassFactoryT>
|
|
|
|
ArchiveTestCase<ClassFactoryT>::ArchiveTestCase(
|
2004-11-23 08:49:43 -05:00
|
|
|
string name,
|
2005-02-10 09:06:08 -05:00
|
|
|
ClassFactoryT *factory,
|
2004-11-23 08:49:43 -05:00
|
|
|
int options,
|
|
|
|
const wxString& archiver,
|
|
|
|
const wxString& unarchiver)
|
|
|
|
:
|
2005-12-18 08:58:55 -05:00
|
|
|
CppUnit::TestCase(TestId::MakeId() + name),
|
2005-02-10 09:06:08 -05:00
|
|
|
m_factory(factory),
|
2004-11-23 08:49:43 -05:00
|
|
|
m_options(options),
|
2005-02-10 09:06:08 -05:00
|
|
|
m_timeStamp(1, wxDateTime::Mar, 2004, 12, 0),
|
2005-12-18 08:58:55 -05:00
|
|
|
m_id(TestId::GetId()),
|
2004-11-23 08:49:43 -05:00
|
|
|
m_archiver(archiver),
|
|
|
|
m_unarchiver(unarchiver)
|
2004-11-10 18:58:38 -05:00
|
|
|
{
|
2004-11-23 08:49:43 -05:00
|
|
|
wxASSERT(m_factory.get() != NULL);
|
2004-11-10 18:58:38 -05:00
|
|
|
}
|
2005-01-18 14:50:43 -05:00
|
|
|
|
2005-02-10 09:06:08 -05:00
|
|
|
template <class ClassFactoryT>
|
|
|
|
ArchiveTestCase<ClassFactoryT>::~ArchiveTestCase()
|
2004-11-10 18:58:38 -05:00
|
|
|
{
|
|
|
|
TestEntries::iterator it;
|
|
|
|
for (it = m_testEntries.begin(); it != m_testEntries.end(); ++it)
|
|
|
|
delete it->second;
|
|
|
|
}
|
|
|
|
|
2005-02-10 09:06:08 -05:00
|
|
|
template <class ClassFactoryT>
|
|
|
|
void ArchiveTestCase<ClassFactoryT>::runTest()
|
2004-11-10 18:58:38 -05:00
|
|
|
{
|
|
|
|
TestOutputStream out(m_options);
|
|
|
|
|
|
|
|
CreateTestData();
|
|
|
|
|
|
|
|
if (m_archiver.empty())
|
|
|
|
CreateArchive(out);
|
|
|
|
else
|
2020-05-08 02:01:56 -04:00
|
|
|
{
|
|
|
|
#ifndef __WXOSX_IPHONE__
|
2004-11-10 18:58:38 -05:00
|
|
|
CreateArchive(out, m_archiver);
|
2020-05-08 02:01:56 -04:00
|
|
|
#else
|
|
|
|
CPPUNIT_FAIL("using external archivers is not supported on iOS");
|
|
|
|
#endif
|
|
|
|
}
|
2004-11-10 18:58:38 -05:00
|
|
|
|
|
|
|
// check archive could be created
|
2004-11-11 14:10:35 -05:00
|
|
|
CPPUNIT_ASSERT(out.GetLength() > 0);
|
2004-11-10 18:58:38 -05:00
|
|
|
|
2005-12-18 08:58:55 -05:00
|
|
|
TestInputStream in(out, m_id % ((m_options & PipeIn) ? 4 : 3));
|
2004-11-10 18:58:38 -05:00
|
|
|
|
|
|
|
TestIterator(in);
|
|
|
|
in.Rewind();
|
|
|
|
TestPairIterator(in);
|
|
|
|
in.Rewind();
|
|
|
|
TestSmartIterator(in);
|
|
|
|
in.Rewind();
|
|
|
|
TestSmartPairIterator(in);
|
|
|
|
in.Rewind();
|
|
|
|
|
|
|
|
if ((m_options & PipeIn) == 0) {
|
|
|
|
ReadSimultaneous(in);
|
|
|
|
in.Rewind();
|
|
|
|
}
|
|
|
|
|
|
|
|
ModifyArchive(in, out);
|
|
|
|
in.SetData(out);
|
|
|
|
|
|
|
|
if (m_unarchiver.empty())
|
|
|
|
ExtractArchive(in);
|
|
|
|
else
|
2020-05-08 02:01:56 -04:00
|
|
|
{
|
|
|
|
#ifndef __WXOSX_IPHONE__
|
2004-11-10 18:58:38 -05:00
|
|
|
ExtractArchive(in, m_unarchiver);
|
2020-05-08 02:01:56 -04:00
|
|
|
#else
|
|
|
|
CPPUNIT_FAIL("using external archivers is not supported on iOS");
|
|
|
|
#endif
|
|
|
|
}
|
2005-01-18 14:50:43 -05:00
|
|
|
|
2004-11-10 18:58:38 -05:00
|
|
|
// check that all the test entries were found in the archive
|
|
|
|
CPPUNIT_ASSERT(m_testEntries.empty());
|
|
|
|
}
|
|
|
|
|
2005-02-10 09:06:08 -05:00
|
|
|
template <class ClassFactoryT>
|
|
|
|
void ArchiveTestCase<ClassFactoryT>::CreateTestData()
|
2004-11-10 18:58:38 -05:00
|
|
|
{
|
|
|
|
Add("text/");
|
|
|
|
Add("text/empty", "");
|
|
|
|
Add("text/small", "Small text file for testing\n"
|
|
|
|
"archive streams in wxWidgets\n");
|
|
|
|
|
|
|
|
Add("bin/");
|
|
|
|
Add("bin/bin1000", 1000);
|
|
|
|
Add("bin/bin4095", 4095);
|
|
|
|
Add("bin/bin4096", 4096);
|
|
|
|
Add("bin/bin4097", 4097);
|
|
|
|
Add("bin/bin16384", 16384);
|
|
|
|
|
|
|
|
Add("zero/");
|
|
|
|
Add("zero/zero5", 5, 0);
|
|
|
|
Add("zero/zero1024", 1024, 109);
|
|
|
|
Add("zero/zero32768", 32768, 106);
|
|
|
|
Add("zero/zero16385", 16385, 119);
|
|
|
|
|
|
|
|
Add("empty/");
|
|
|
|
}
|
|
|
|
|
2005-02-10 09:06:08 -05:00
|
|
|
template <class ClassFactoryT>
|
|
|
|
TestEntry& ArchiveTestCase<ClassFactoryT>::Add(const char *name,
|
|
|
|
const char *data,
|
|
|
|
int len /*=-1*/)
|
2004-11-10 18:58:38 -05:00
|
|
|
{
|
|
|
|
if (len == -1)
|
|
|
|
len = strlen(data);
|
|
|
|
TestEntry*& entry = m_testEntries[wxString(name, *wxConvCurrent)];
|
|
|
|
wxASSERT(entry == NULL);
|
|
|
|
entry = new TestEntry(m_timeStamp, len, data);
|
|
|
|
m_timeStamp += wxTimeSpan(0, 1, 30);
|
|
|
|
return *entry;
|
|
|
|
}
|
|
|
|
|
2005-02-10 09:06:08 -05:00
|
|
|
template <class ClassFactoryT>
|
|
|
|
TestEntry& ArchiveTestCase<ClassFactoryT>::Add(const char *name,
|
|
|
|
int len /*=0*/,
|
|
|
|
int value /*=EOF*/)
|
2004-11-10 18:58:38 -05:00
|
|
|
{
|
|
|
|
wxCharBuffer buf(len);
|
|
|
|
for (int i = 0; i < len; i++)
|
2004-11-25 15:37:44 -05:00
|
|
|
buf.data()[i] = (char)(value == EOF ? rand() : value);
|
2004-11-10 18:58:38 -05:00
|
|
|
return Add(name, buf, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create an archive using the wx archive classes, write it to 'out'
|
|
|
|
//
|
2005-02-10 09:06:08 -05:00
|
|
|
template <class ClassFactoryT>
|
|
|
|
void ArchiveTestCase<ClassFactoryT>::CreateArchive(wxOutputStream& out)
|
2004-11-10 18:58:38 -05:00
|
|
|
{
|
2016-02-13 07:36:58 -05:00
|
|
|
wxScopedPtr<OutputStreamT> arc(m_factory->NewStream(out));
|
2004-11-10 18:58:38 -05:00
|
|
|
TestEntries::iterator it;
|
|
|
|
|
|
|
|
OnCreateArchive(*arc);
|
|
|
|
|
|
|
|
// We want to try creating entries in various different ways, 'choices'
|
|
|
|
// is just a number used to select between all the various possibilities.
|
|
|
|
int choices = m_id;
|
|
|
|
|
|
|
|
for (it = m_testEntries.begin(); it != m_testEntries.end(); ++it) {
|
|
|
|
choices += 5;
|
|
|
|
TestEntry& testEntry = *it->second;
|
|
|
|
wxString name = it->first;
|
|
|
|
|
|
|
|
// 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
|
2009-07-23 16:30:22 -04:00
|
|
|
bool setIsDir = name.Last() == wxT('/') && (choices & 1);
|
2004-11-10 18:58:38 -05:00
|
|
|
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
|
2009-07-23 16:30:22 -04:00
|
|
|
string error_entry((wxT(" '") + name + wxT("'")).mb_str());
|
2004-11-23 08:49:43 -05:00
|
|
|
string error_context(" failed for entry" + error_entry);
|
2004-11-10 18:58:38 -05:00
|
|
|
|
|
|
|
if ((choices & 2) || testEntry.IsText()) {
|
|
|
|
// try PutNextEntry(EntryT *pEntry)
|
2016-02-13 07:36:58 -05:00
|
|
|
wxScopedPtr<EntryT> entry(m_factory->NewEntry());
|
2004-11-10 18:58:38 -05:00
|
|
|
entry->SetName(name, wxPATH_UNIX);
|
|
|
|
if (setIsDir)
|
|
|
|
entry->SetIsDir();
|
|
|
|
entry->SetDateTime(testEntry.GetDateTime());
|
|
|
|
entry->SetSize(testEntry.GetLength());
|
|
|
|
OnCreateEntry(*arc, testEntry, entry.get());
|
|
|
|
CPPUNIT_ASSERT_MESSAGE("PutNextEntry" + error_context,
|
|
|
|
arc->PutNextEntry(entry.release()));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// try the convenience methods
|
|
|
|
OnCreateEntry(*arc, testEntry);
|
|
|
|
if (setIsDir)
|
|
|
|
CPPUNIT_ASSERT_MESSAGE("PutNextDirEntry" + error_context,
|
|
|
|
arc->PutNextDirEntry(name, testEntry.GetDateTime()));
|
|
|
|
else
|
|
|
|
CPPUNIT_ASSERT_MESSAGE("PutNextEntry" + error_context,
|
|
|
|
arc->PutNextEntry(name, testEntry.GetDateTime(),
|
|
|
|
testEntry.GetLength()));
|
|
|
|
}
|
|
|
|
|
2009-07-23 16:30:22 -04:00
|
|
|
if (it->first.Last() != wxT('/')) {
|
2004-11-10 18:58:38 -05:00
|
|
|
// for non-dirs write the data
|
|
|
|
arc->Write(testEntry.GetData(), testEntry.GetSize());
|
|
|
|
CPPUNIT_ASSERT_MESSAGE("LastWrite check" + error_context,
|
|
|
|
arc->LastWrite() == testEntry.GetSize());
|
|
|
|
// should work with or without explicit CloseEntry
|
|
|
|
if (choices & 3)
|
|
|
|
CPPUNIT_ASSERT_MESSAGE("CloseEntry" + error_context,
|
|
|
|
arc->CloseEntry());
|
|
|
|
}
|
|
|
|
|
|
|
|
CPPUNIT_ASSERT_MESSAGE("IsOk" + error_context, arc->IsOk());
|
|
|
|
}
|
|
|
|
|
|
|
|
// should work with or without explicit Close
|
|
|
|
if (m_id % 2)
|
|
|
|
CPPUNIT_ASSERT(arc->Close());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create an archive using an external archive program
|
|
|
|
//
|
2020-05-08 02:01:56 -04:00
|
|
|
#ifndef __WXOSX_IPHONE__
|
2005-02-10 09:06:08 -05:00
|
|
|
template <class ClassFactoryT>
|
|
|
|
void ArchiveTestCase<ClassFactoryT>::CreateArchive(wxOutputStream& out,
|
|
|
|
const wxString& archiver)
|
2004-11-10 18:58:38 -05:00
|
|
|
{
|
|
|
|
// for an external archiver the test data need to be written to
|
|
|
|
// temp files
|
|
|
|
TempDir tmpdir;
|
|
|
|
|
|
|
|
// write the files
|
|
|
|
TestEntries::iterator i;
|
|
|
|
for (i = m_testEntries.begin(); i != m_testEntries.end(); ++i) {
|
|
|
|
wxFileName fn(i->first, wxPATH_UNIX);
|
|
|
|
TestEntry& entry = *i->second;
|
|
|
|
|
|
|
|
if (fn.IsDir()) {
|
2009-06-17 13:31:53 -04:00
|
|
|
wxFileName::Mkdir(fn.GetPath(), 0777, wxPATH_MKDIR_FULL);
|
2004-11-10 18:58:38 -05:00
|
|
|
} else {
|
|
|
|
wxFileName::Mkdir(fn.GetPath(), 0777, wxPATH_MKDIR_FULL);
|
|
|
|
wxFFileOutputStream fileout(fn.GetFullPath());
|
|
|
|
fileout.Write(entry.GetData(), entry.GetSize());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = m_testEntries.begin(); i != m_testEntries.end(); ++i) {
|
|
|
|
wxFileName fn(i->first, wxPATH_UNIX);
|
|
|
|
TestEntry& entry = *i->second;
|
|
|
|
wxDateTime dt = entry.GetDateTime();
|
2012-03-04 15:31:42 -05:00
|
|
|
#ifdef __WINDOWS__
|
2004-11-10 18:58:38 -05:00
|
|
|
if (fn.IsDir())
|
|
|
|
entry.SetDateTime(wxDateTime());
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
fn.SetTimes(NULL, &dt, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((m_options & PipeOut) == 0) {
|
|
|
|
wxFileName fn(tmpdir.GetName());
|
2009-07-23 16:30:22 -04:00
|
|
|
fn.SetExt(wxT("arc"));
|
2005-02-10 09:06:08 -05:00
|
|
|
wxString tmparc = fn.GetPath(wxPATH_GET_SEPARATOR) + fn.GetFullName();
|
2004-11-10 18:58:38 -05:00
|
|
|
|
|
|
|
// call the archiver to create an archive file
|
2021-07-04 09:28:55 -04:00
|
|
|
if ( system(wxString::Format(archiver, tmparc).mb_str()) == -1 )
|
2012-10-20 10:49:13 -04:00
|
|
|
{
|
|
|
|
wxLogError("Failed to run acrhiver command \"%s\"", archiver);
|
|
|
|
}
|
2004-11-10 18:58:38 -05:00
|
|
|
|
|
|
|
// then load the archive file
|
|
|
|
{
|
|
|
|
wxFFileInputStream in(tmparc);
|
2011-05-03 12:29:04 -04:00
|
|
|
if (in.IsOk())
|
2004-11-10 18:58:38 -05:00
|
|
|
out.Write(in);
|
|
|
|
}
|
|
|
|
|
|
|
|
wxRemoveFile(tmparc);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// for the non-seekable test, have the archiver output to "-"
|
|
|
|
// and read the archive via a pipe
|
2009-07-23 16:30:22 -04:00
|
|
|
PFileInputStream in(wxString::Format(archiver, wxT("-")));
|
2011-05-03 12:29:04 -04:00
|
|
|
if (in.IsOk())
|
2004-11-10 18:58:38 -05:00
|
|
|
out.Write(in);
|
|
|
|
}
|
|
|
|
}
|
2020-05-08 02:01:56 -04:00
|
|
|
#endif
|
2004-11-10 18:58:38 -05:00
|
|
|
|
|
|
|
// Do a standard set of modification on an archive, delete an entry,
|
|
|
|
// rename an entry and add an entry
|
|
|
|
//
|
2005-02-10 09:06:08 -05:00
|
|
|
template <class ClassFactoryT>
|
|
|
|
void ArchiveTestCase<ClassFactoryT>::ModifyArchive(wxInputStream& in,
|
|
|
|
wxOutputStream& out)
|
2004-11-10 18:58:38 -05:00
|
|
|
{
|
2016-02-13 07:36:58 -05:00
|
|
|
wxScopedPtr<InputStreamT> arcIn(m_factory->NewStream(in));
|
|
|
|
wxScopedPtr<OutputStreamT> arcOut(m_factory->NewStream(out));
|
2004-11-25 15:37:44 -05:00
|
|
|
EntryT *pEntry;
|
2004-11-10 18:58:38 -05:00
|
|
|
|
2009-07-23 16:30:22 -04:00
|
|
|
const wxString deleteName = wxT("bin/bin1000");
|
|
|
|
const wxString renameFrom = wxT("zero/zero1024");
|
|
|
|
const wxString renameTo = wxT("zero/newname");
|
|
|
|
const wxString newName = wxT("newfile");
|
2004-11-10 18:58:38 -05:00
|
|
|
const char *newData = "New file added as a test\n";
|
|
|
|
|
|
|
|
arcOut->CopyArchiveMetaData(*arcIn);
|
|
|
|
|
2004-11-25 15:37:44 -05:00
|
|
|
while ((pEntry = arcIn->GetNextEntry()) != NULL) {
|
2016-02-13 07:36:58 -05:00
|
|
|
wxScopedPtr<EntryT> entry(pEntry);
|
2004-11-25 15:37:44 -05:00
|
|
|
OnSetNotifier(*entry);
|
|
|
|
wxString name = entry->GetName(wxPATH_UNIX);
|
2004-11-10 18:58:38 -05:00
|
|
|
|
|
|
|
// provide some context for the error message so that we know which
|
|
|
|
// iteration of the loop we were on
|
2009-07-23 16:30:22 -04:00
|
|
|
string error_entry((wxT(" '") + name + wxT("'")).mb_str());
|
2004-11-23 08:49:43 -05:00
|
|
|
string error_context(" failed for entry" + error_entry);
|
2004-11-10 18:58:38 -05:00
|
|
|
|
|
|
|
if (name == deleteName) {
|
|
|
|
TestEntries::iterator it = m_testEntries.find(name);
|
|
|
|
CPPUNIT_ASSERT_MESSAGE(
|
|
|
|
"deletion failed (already deleted?) for" + error_entry,
|
|
|
|
it != m_testEntries.end());
|
|
|
|
TestEntry *p = it->second;
|
|
|
|
m_testEntries.erase(it);
|
|
|
|
delete p;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (name == renameFrom) {
|
2004-11-25 15:37:44 -05:00
|
|
|
entry->SetName(renameTo);
|
2004-11-10 18:58:38 -05:00
|
|
|
TestEntries::iterator it = m_testEntries.find(renameFrom);
|
|
|
|
CPPUNIT_ASSERT_MESSAGE(
|
|
|
|
"rename failed (already renamed?) for" + error_entry,
|
|
|
|
it != m_testEntries.end());
|
|
|
|
TestEntry *p = it->second;
|
|
|
|
m_testEntries.erase(it);
|
|
|
|
m_testEntries[renameTo] = p;
|
|
|
|
}
|
|
|
|
|
|
|
|
CPPUNIT_ASSERT_MESSAGE("CopyEntry" + error_context,
|
2004-11-25 15:37:44 -05:00
|
|
|
arcOut->CopyEntry(entry.release(), *arcIn));
|
2004-11-10 18:58:38 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// check that the deletion and rename were done
|
|
|
|
CPPUNIT_ASSERT(m_testEntries.count(deleteName) == 0);
|
|
|
|
CPPUNIT_ASSERT(m_testEntries.count(renameFrom) == 0);
|
|
|
|
CPPUNIT_ASSERT(m_testEntries.count(renameTo) == 1);
|
|
|
|
|
|
|
|
// check that the end of the input archive was reached without error
|
|
|
|
CPPUNIT_ASSERT(arcIn->Eof());
|
|
|
|
|
|
|
|
// try adding a new entry
|
|
|
|
TestEntry& testEntry = Add(newName.mb_str(), newData);
|
2016-02-13 07:36:58 -05:00
|
|
|
wxScopedPtr<EntryT> newentry(m_factory->NewEntry());
|
2004-11-23 08:49:43 -05:00
|
|
|
newentry->SetName(newName);
|
|
|
|
newentry->SetDateTime(testEntry.GetDateTime());
|
|
|
|
newentry->SetSize(testEntry.GetLength());
|
|
|
|
OnCreateEntry(*arcOut, testEntry, newentry.get());
|
|
|
|
OnSetNotifier(*newentry);
|
|
|
|
CPPUNIT_ASSERT(arcOut->PutNextEntry(newentry.release()));
|
2004-11-10 18:58:38 -05:00
|
|
|
CPPUNIT_ASSERT(arcOut->Write(newData, strlen(newData)).IsOk());
|
|
|
|
|
|
|
|
// should work with or without explicit Close
|
|
|
|
if (m_id % 2)
|
|
|
|
CPPUNIT_ASSERT(arcOut->Close());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Extract an archive using the wx archive classes
|
|
|
|
//
|
2005-02-10 09:06:08 -05:00
|
|
|
template <class ClassFactoryT>
|
|
|
|
void ArchiveTestCase<ClassFactoryT>::ExtractArchive(wxInputStream& in)
|
2004-11-10 18:58:38 -05:00
|
|
|
{
|
|
|
|
typedef Ptr<EntryT> EntryPtr;
|
|
|
|
typedef std::list<EntryPtr> Entries;
|
|
|
|
typedef typename Entries::iterator EntryIter;
|
|
|
|
|
2016-02-13 07:36:58 -05:00
|
|
|
wxScopedPtr<InputStreamT> arc(m_factory->NewStream(in));
|
2004-11-10 18:58:38 -05:00
|
|
|
int expectedTotal = m_testEntries.size();
|
|
|
|
EntryPtr entry;
|
|
|
|
Entries entries;
|
|
|
|
|
|
|
|
if ((m_options & PipeIn) == 0)
|
|
|
|
OnArchiveExtracted(*arc, expectedTotal);
|
|
|
|
|
|
|
|
while (entry = EntryPtr(arc->GetNextEntry()), entry.get() != NULL) {
|
|
|
|
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
|
2009-07-23 16:30:22 -04:00
|
|
|
string error_entry((wxT(" '") + name + wxT("'")).mb_str());
|
2004-11-23 08:49:43 -05:00
|
|
|
string error_context(" failed for entry" + error_entry);
|
2004-11-10 18:58:38 -05:00
|
|
|
|
|
|
|
TestEntries::iterator it = m_testEntries.find(name);
|
|
|
|
CPPUNIT_ASSERT_MESSAGE(
|
|
|
|
"archive contains an entry that shouldn't be there" + error_entry,
|
|
|
|
it != m_testEntries.end());
|
|
|
|
|
|
|
|
const TestEntry& testEntry = *it->second;
|
|
|
|
|
2012-03-04 15:31:42 -05:00
|
|
|
#ifndef __WINDOWS__
|
2009-04-04 18:12:04 -04:00
|
|
|
// On Windows some archivers compensate for Windows DST handling, but
|
|
|
|
// other don't, so disable the test for now.
|
2004-11-10 18:58:38 -05:00
|
|
|
wxDateTime dt = testEntry.GetDateTime();
|
|
|
|
if (dt.IsValid())
|
|
|
|
CPPUNIT_ASSERT_MESSAGE("timestamp check" + error_context,
|
|
|
|
dt == entry->GetDateTime());
|
2009-04-04 18:12:04 -04:00
|
|
|
#endif
|
2004-11-10 18:58:38 -05:00
|
|
|
|
|
|
|
// non-seekable entries are allowed to have GetSize == wxInvalidOffset
|
|
|
|
// until the end of the entry's data has been read past
|
|
|
|
CPPUNIT_ASSERT_MESSAGE("entry size check" + error_context,
|
Replace CppUnit with Catch for unit tests
Drop the legacy CppUnit testing framework used for the unit tests.
Replacing it with Catch has the advantage of not requiring CppUnit
libraries to be installed on the system in order to be able to run
tests (Catch is header-only and a copy of it is now included in the
main repository itself) and, in the future, of being able to write
the tests in a much more natural way.
For now, however, avoid changing the existing tests code as much as
[reasonably] possible to avoid introducing bugs in them and provide
the CppUnit compatibility macros in the new wx/catch_cppunit.h header
which allow to preserve the 99% of the existing code unchanged. Some
of the required changes are:
- Decompose asserts using "a && b" conditions into multiple asserts
checking "a" and "b" independently. This would have been better
even with CppUnit (to know which part of condition exactly failed)
and is required with Catch.
- Use extra parentheses around such conditions when they can't be
easily decomposed in the arrays test, due to the use of macros.
This is not ideal from the point of view of messages given when
the tests fail but will do for now.
- Rewrite asserts using "a || b" as a combination of condition
checks and assert macros. Again, this is better anyhow, and is
required with Catch. Incidentally, this allowed to fix a bug in
the "exec" unit test which didn't leave enough time for the new
process to be launched before trying to kill it.
- Remove multiple CPPUNIT_TEST_SUITE_NAMED_REGISTRATION() macros,
our emulation of this macro can be used only once.
- Provide string conversions using Catch-specific StringMaker for
a couple of types.
- Replace custom wxImage comparison with a Catch-specific matcher
class.
- Remove most of test running logic from test.cpp, in particular don't
parse command line ourselves any longer but use Catch built-in
command line parser. This is a source of a minor regression:
previously, both "Foo" and "FooTestCase" could be used as the name of
the test to run, but now only the latter is accepted.
2017-11-01 14:15:24 -04:00
|
|
|
(testEntry.GetLength() == entry->GetSize() ||
|
|
|
|
((m_options & PipeIn) != 0 && entry->GetSize() == wxInvalidOffset)));
|
2004-11-10 18:58:38 -05:00
|
|
|
CPPUNIT_ASSERT_MESSAGE(
|
2004-11-11 14:10:35 -05:00
|
|
|
"arc->GetLength() == entry->GetSize()" + error_context,
|
|
|
|
arc->GetLength() == entry->GetSize());
|
2004-11-10 18:58:38 -05:00
|
|
|
|
2009-07-23 16:30:22 -04:00
|
|
|
if (name.Last() != wxT('/'))
|
2004-11-10 18:58:38 -05:00
|
|
|
{
|
|
|
|
CPPUNIT_ASSERT_MESSAGE("!IsDir" + error_context,
|
|
|
|
!entry->IsDir());
|
|
|
|
wxCharBuffer buf(testEntry.GetSize() + 1);
|
|
|
|
CPPUNIT_ASSERT_MESSAGE("Read until Eof" + error_context,
|
|
|
|
arc->Read(buf.data(), testEntry.GetSize() + 1).Eof());
|
|
|
|
CPPUNIT_ASSERT_MESSAGE("LastRead check" + error_context,
|
|
|
|
arc->LastRead() == testEntry.GetSize());
|
|
|
|
CPPUNIT_ASSERT_MESSAGE("data compare" + error_context,
|
|
|
|
!memcmp(buf.data(), testEntry.GetData(), testEntry.GetSize()));
|
|
|
|
} else {
|
|
|
|
CPPUNIT_ASSERT_MESSAGE("IsDir" + error_context, entry->IsDir());
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetSize() must return the right result in all cases after all the
|
|
|
|
// data has been read
|
|
|
|
CPPUNIT_ASSERT_MESSAGE("entry size check" + error_context,
|
|
|
|
testEntry.GetLength() == entry->GetSize());
|
|
|
|
CPPUNIT_ASSERT_MESSAGE(
|
2004-11-11 14:10:35 -05:00
|
|
|
"arc->GetLength() == entry->GetSize()" + error_context,
|
|
|
|
arc->GetLength() == entry->GetSize());
|
2004-11-10 18:58:38 -05:00
|
|
|
|
|
|
|
if ((m_options & PipeIn) == 0) {
|
|
|
|
OnEntryExtracted(*entry, testEntry, arc.get());
|
|
|
|
delete it->second;
|
|
|
|
m_testEntries.erase(it);
|
|
|
|
} else {
|
|
|
|
entries.push_back(entry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// check that the end of the input archive was reached without error
|
|
|
|
CPPUNIT_ASSERT(arc->Eof());
|
|
|
|
|
|
|
|
// for non-seekable streams these data are only guaranteed to be
|
|
|
|
// available once the end of the archive has been reached
|
|
|
|
if (m_options & PipeIn) {
|
|
|
|
for (EntryIter i = entries.begin(); i != entries.end(); ++i) {
|
|
|
|
wxString name = (*i)->GetName(wxPATH_UNIX);
|
|
|
|
TestEntries::iterator j = m_testEntries.find(name);
|
|
|
|
OnEntryExtracted(**i, *j->second);
|
|
|
|
delete j->second;
|
|
|
|
m_testEntries.erase(j);
|
|
|
|
}
|
|
|
|
OnArchiveExtracted(*arc, expectedTotal);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Extract an archive using an external unarchive program
|
|
|
|
//
|
2020-05-08 02:01:56 -04:00
|
|
|
#ifndef __WXOSX_IPHONE__
|
2005-02-10 09:06:08 -05:00
|
|
|
template <class ClassFactoryT>
|
|
|
|
void ArchiveTestCase<ClassFactoryT>::ExtractArchive(wxInputStream& in,
|
|
|
|
const wxString& unarchiver)
|
2004-11-10 18:58:38 -05:00
|
|
|
{
|
|
|
|
// for an external unarchiver, unarchive to a tempdir
|
|
|
|
TempDir tmpdir;
|
|
|
|
|
|
|
|
if ((m_options & PipeIn) == 0) {
|
|
|
|
wxFileName fn(tmpdir.GetName());
|
2009-07-23 16:30:22 -04:00
|
|
|
fn.SetExt(wxT("arc"));
|
2005-02-10 09:06:08 -05:00
|
|
|
wxString tmparc = fn.GetPath(wxPATH_GET_SEPARATOR) + fn.GetFullName();
|
2005-01-18 14:50:43 -05:00
|
|
|
|
2004-11-10 18:58:38 -05:00
|
|
|
if (m_options & Stub)
|
2005-02-10 09:06:08 -05:00
|
|
|
in.SeekI(STUB_SIZE * 2);
|
2004-11-10 18:58:38 -05:00
|
|
|
|
|
|
|
// write the archive to a temporary file
|
|
|
|
{
|
|
|
|
wxFFileOutputStream out(tmparc);
|
2011-05-03 12:29:04 -04:00
|
|
|
if (out.IsOk())
|
2004-11-10 18:58:38 -05:00
|
|
|
out.Write(in);
|
|
|
|
}
|
|
|
|
|
|
|
|
// call unarchiver
|
2021-07-04 09:28:55 -04:00
|
|
|
if ( system(wxString::Format(unarchiver, tmparc).mb_str()) == -1 )
|
2012-10-20 10:49:13 -04:00
|
|
|
{
|
|
|
|
wxLogError("Failed to run unarchiver command \"%s\"", unarchiver);
|
|
|
|
}
|
|
|
|
|
2004-11-10 18:58:38 -05:00
|
|
|
wxRemoveFile(tmparc);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// for the non-seekable test, have the archiver extract "-" and
|
|
|
|
// feed it the archive via a pipe
|
2009-07-23 16:30:22 -04:00
|
|
|
PFileOutputStream out(wxString::Format(unarchiver, wxT("-")));
|
2011-05-03 12:29:04 -04:00
|
|
|
if (out.IsOk())
|
2004-11-10 18:58:38 -05:00
|
|
|
out.Write(in);
|
|
|
|
}
|
|
|
|
|
|
|
|
wxString dir = tmpdir.GetName();
|
|
|
|
VerifyDir(dir);
|
|
|
|
}
|
2020-05-08 02:01:56 -04:00
|
|
|
#endif
|
2004-11-10 18:58:38 -05:00
|
|
|
|
|
|
|
// Verifies the files produced by an external unarchiver are as expected
|
|
|
|
//
|
2005-02-10 09:06:08 -05:00
|
|
|
template <class ClassFactoryT>
|
|
|
|
void ArchiveTestCase<ClassFactoryT>::VerifyDir(wxString& path,
|
|
|
|
size_t rootlen /*=0*/)
|
2004-11-10 18:58:38 -05:00
|
|
|
{
|
|
|
|
wxDir dir;
|
|
|
|
path += wxFileName::GetPathSeparator();
|
|
|
|
int pos = path.length();
|
|
|
|
wxString name;
|
|
|
|
|
|
|
|
if (!rootlen)
|
|
|
|
rootlen = pos;
|
|
|
|
|
|
|
|
if (dir.Open(path) && dir.GetFirst(&name)) {
|
|
|
|
do {
|
|
|
|
path.replace(pos, wxString::npos, name);
|
|
|
|
name = m_factory->GetInternalName(
|
|
|
|
path.substr(rootlen, wxString::npos));
|
|
|
|
|
2005-04-05 12:10:48 -04:00
|
|
|
bool isDir = wxDirExists(path);
|
2004-11-10 18:58:38 -05:00
|
|
|
if (isDir)
|
2009-07-23 16:30:22 -04:00
|
|
|
name += wxT("/");
|
2004-11-10 18:58:38 -05:00
|
|
|
|
|
|
|
// provide some context for the error message so that we know which
|
|
|
|
// iteration of the loop we were on
|
2009-07-23 16:30:22 -04:00
|
|
|
string error_entry((wxT(" '") + name + wxT("'")).mb_str());
|
2004-11-23 08:49:43 -05:00
|
|
|
string error_context(" failed for entry" + error_entry);
|
2004-11-10 18:58:38 -05:00
|
|
|
|
|
|
|
TestEntries::iterator it = m_testEntries.find(name);
|
|
|
|
CPPUNIT_ASSERT_MESSAGE(
|
|
|
|
"archive contains an entry that shouldn't be there"
|
|
|
|
+ error_entry,
|
|
|
|
it != m_testEntries.end());
|
|
|
|
|
|
|
|
const TestEntry& testEntry = *it->second;
|
|
|
|
|
2012-03-04 15:31:42 -05:00
|
|
|
#if 0 //ndef __WINDOWS__
|
2004-11-10 18:58:38 -05:00
|
|
|
CPPUNIT_ASSERT_MESSAGE("timestamp check" + error_context,
|
|
|
|
testEntry.GetDateTime() ==
|
|
|
|
wxFileName(path).GetModificationTime());
|
|
|
|
#endif
|
|
|
|
if (!isDir) {
|
|
|
|
wxFFileInputStream in(path);
|
|
|
|
CPPUNIT_ASSERT_MESSAGE(
|
2011-05-03 12:29:04 -04:00
|
|
|
"entry not found in archive" + error_entry, in.IsOk());
|
2004-11-10 18:58:38 -05:00
|
|
|
|
2004-11-25 15:37:44 -05:00
|
|
|
size_t size = (size_t)in.GetLength();
|
2004-11-10 18:58:38 -05:00
|
|
|
wxCharBuffer buf(size);
|
|
|
|
CPPUNIT_ASSERT_MESSAGE("Read" + error_context,
|
|
|
|
in.Read(buf.data(), size).LastRead() == size);
|
|
|
|
CPPUNIT_ASSERT_MESSAGE("size check" + error_context,
|
|
|
|
testEntry.GetSize() == size);
|
|
|
|
CPPUNIT_ASSERT_MESSAGE("data compare" + error_context,
|
|
|
|
memcmp(buf.data(), testEntry.GetData(), size) == 0);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
VerifyDir(path, rootlen);
|
|
|
|
}
|
|
|
|
|
|
|
|
delete it->second;
|
|
|
|
m_testEntries.erase(it);
|
|
|
|
}
|
|
|
|
while (dir.GetNext(&name));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// test the simple iterators that give away ownership of an entry
|
|
|
|
//
|
2005-02-10 09:06:08 -05:00
|
|
|
template <class ClassFactoryT>
|
|
|
|
void ArchiveTestCase<ClassFactoryT>::TestIterator(wxInputStream& in)
|
2004-11-10 18:58:38 -05:00
|
|
|
{
|
|
|
|
typedef std::list<EntryT*> ArchiveCatalog;
|
|
|
|
typedef typename ArchiveCatalog::iterator CatalogIter;
|
|
|
|
|
2016-02-13 07:36:58 -05:00
|
|
|
wxScopedPtr<InputStreamT> arc(m_factory->NewStream(in));
|
2004-11-10 18:58:38 -05:00
|
|
|
size_t count = 0;
|
|
|
|
|
|
|
|
#ifdef WXARC_MEMBER_TEMPLATES
|
|
|
|
ArchiveCatalog cat((IterT)*arc, IterT());
|
|
|
|
#else
|
|
|
|
ArchiveCatalog cat;
|
|
|
|
for (IterT i(*arc); i != IterT(); ++i)
|
|
|
|
cat.push_back(*i);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
for (CatalogIter it = cat.begin(); it != cat.end(); ++it) {
|
2016-02-13 07:36:58 -05:00
|
|
|
wxScopedPtr<EntryT> entry(*it);
|
2004-11-10 18:58:38 -05:00
|
|
|
count += m_testEntries.count(entry->GetName(wxPATH_UNIX));
|
|
|
|
}
|
|
|
|
|
|
|
|
CPPUNIT_ASSERT(m_testEntries.size() == cat.size());
|
|
|
|
CPPUNIT_ASSERT(count == cat.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
// test the pair iterators that can be used to load a std::map or wxHashMap
|
|
|
|
// these also give away ownership of entries
|
|
|
|
//
|
2005-02-10 09:06:08 -05:00
|
|
|
template <class ClassFactoryT>
|
|
|
|
void ArchiveTestCase<ClassFactoryT>::TestPairIterator(wxInputStream& in)
|
2004-11-10 18:58:38 -05:00
|
|
|
{
|
|
|
|
typedef std::map<wxString, EntryT*> ArchiveCatalog;
|
|
|
|
typedef typename ArchiveCatalog::iterator CatalogIter;
|
|
|
|
|
2016-02-13 07:36:58 -05:00
|
|
|
wxScopedPtr<InputStreamT> arc(m_factory->NewStream(in));
|
2004-11-10 18:58:38 -05:00
|
|
|
size_t count = 0;
|
|
|
|
|
|
|
|
#ifdef WXARC_MEMBER_TEMPLATES
|
|
|
|
ArchiveCatalog cat((PairIterT)*arc, PairIterT());
|
|
|
|
#else
|
|
|
|
ArchiveCatalog cat;
|
|
|
|
for (PairIterT i(*arc); i != PairIterT(); ++i)
|
2004-11-23 08:49:43 -05:00
|
|
|
cat.insert(*i);
|
2004-11-10 18:58:38 -05:00
|
|
|
#endif
|
|
|
|
|
|
|
|
for (CatalogIter it = cat.begin(); it != cat.end(); ++it) {
|
2016-02-13 07:36:58 -05:00
|
|
|
wxScopedPtr<EntryT> entry(it->second);
|
2004-11-10 18:58:38 -05:00
|
|
|
count += m_testEntries.count(entry->GetName(wxPATH_UNIX));
|
|
|
|
}
|
|
|
|
|
|
|
|
CPPUNIT_ASSERT(m_testEntries.size() == cat.size());
|
|
|
|
CPPUNIT_ASSERT(count == cat.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
// simple iterators using smart pointers, no need to worry about ownership
|
|
|
|
//
|
2005-02-10 09:06:08 -05:00
|
|
|
template <class ClassFactoryT>
|
|
|
|
void ArchiveTestCase<ClassFactoryT>::TestSmartIterator(wxInputStream& in)
|
2004-11-10 18:58:38 -05:00
|
|
|
{
|
|
|
|
typedef std::list<Ptr<EntryT> > ArchiveCatalog;
|
|
|
|
typedef typename ArchiveCatalog::iterator CatalogIter;
|
|
|
|
typedef wxArchiveIterator<InputStreamT, Ptr<EntryT> > Iter;
|
|
|
|
|
2016-02-13 07:36:58 -05:00
|
|
|
wxScopedPtr<InputStreamT> arc(m_factory->NewStream(in));
|
2004-11-10 18:58:38 -05:00
|
|
|
|
|
|
|
#ifdef WXARC_MEMBER_TEMPLATES
|
|
|
|
ArchiveCatalog cat((Iter)*arc, Iter());
|
|
|
|
#else
|
|
|
|
ArchiveCatalog cat;
|
|
|
|
for (Iter i(*arc); i != Iter(); ++i)
|
|
|
|
cat.push_back(*i);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
CPPUNIT_ASSERT(m_testEntries.size() == cat.size());
|
|
|
|
|
|
|
|
for (CatalogIter it = cat.begin(); it != cat.end(); ++it)
|
|
|
|
CPPUNIT_ASSERT(m_testEntries.count((*it)->GetName(wxPATH_UNIX)));
|
|
|
|
}
|
|
|
|
|
|
|
|
// pair iterator using smart pointers
|
|
|
|
//
|
2005-02-10 09:06:08 -05:00
|
|
|
template <class ClassFactoryT>
|
|
|
|
void ArchiveTestCase<ClassFactoryT>::TestSmartPairIterator(wxInputStream& in)
|
2004-11-10 18:58:38 -05:00
|
|
|
{
|
2004-11-25 15:37:44 -05:00
|
|
|
#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
|
2004-11-10 18:58:38 -05:00
|
|
|
typedef std::map<wxString, Ptr<EntryT> > ArchiveCatalog;
|
|
|
|
typedef typename ArchiveCatalog::iterator CatalogIter;
|
|
|
|
typedef wxArchiveIterator<InputStreamT,
|
|
|
|
std::pair<wxString, Ptr<EntryT> > > PairIter;
|
|
|
|
|
2016-02-13 07:36:58 -05:00
|
|
|
wxScopedPtr<InputStreamT> arc(m_factory->NewStream(in));
|
2004-11-10 18:58:38 -05:00
|
|
|
|
|
|
|
#ifdef WXARC_MEMBER_TEMPLATES
|
|
|
|
ArchiveCatalog cat((PairIter)*arc, PairIter());
|
|
|
|
#else
|
|
|
|
ArchiveCatalog cat;
|
|
|
|
for (PairIter i(*arc); i != PairIter(); ++i)
|
2004-11-23 08:49:43 -05:00
|
|
|
cat.insert(*i);
|
2004-11-10 18:58:38 -05:00
|
|
|
#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)));
|
2004-11-25 15:37:44 -05:00
|
|
|
#endif
|
2004-11-10 18:58:38 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// try reading two entries at the same time
|
|
|
|
//
|
2005-02-10 09:06:08 -05:00
|
|
|
template <class ClassFactoryT>
|
|
|
|
void ArchiveTestCase<ClassFactoryT>::ReadSimultaneous(TestInputStream& in)
|
2004-11-10 18:58:38 -05:00
|
|
|
{
|
|
|
|
typedef std::map<wxString, Ptr<EntryT> > ArchiveCatalog;
|
|
|
|
typedef wxArchiveIterator<InputStreamT,
|
|
|
|
std::pair<wxString, Ptr<EntryT> > > PairIter;
|
|
|
|
|
|
|
|
// create two archive input streams
|
|
|
|
TestInputStream in2(in);
|
2016-02-13 07:36:58 -05:00
|
|
|
wxScopedPtr<InputStreamT> arc(m_factory->NewStream(in));
|
|
|
|
wxScopedPtr<InputStreamT> arc2(m_factory->NewStream(in2));
|
2004-11-10 18:58:38 -05:00
|
|
|
|
|
|
|
// load the catalog
|
|
|
|
#ifdef WXARC_MEMBER_TEMPLATES
|
|
|
|
ArchiveCatalog cat((PairIter)*arc, PairIter());
|
|
|
|
#else
|
|
|
|
ArchiveCatalog cat;
|
|
|
|
for (PairIter i(*arc); i != PairIter(); ++i)
|
2004-11-23 08:49:43 -05:00
|
|
|
cat.insert(*i);
|
2004-11-10 18:58:38 -05:00
|
|
|
#endif
|
|
|
|
|
|
|
|
// the names of two entries to read
|
2009-07-23 16:30:22 -04:00
|
|
|
const wxChar *name = wxT("text/small");
|
|
|
|
const wxChar *name2 = wxT("bin/bin1000");
|
2004-11-10 18:58:38 -05:00
|
|
|
|
|
|
|
// open them
|
|
|
|
typename ArchiveCatalog::iterator j;
|
|
|
|
CPPUNIT_ASSERT((j = cat.find(name)) != cat.end());
|
|
|
|
CPPUNIT_ASSERT(arc->OpenEntry(*j->second));
|
|
|
|
CPPUNIT_ASSERT((j = cat.find(name2)) != cat.end());
|
|
|
|
CPPUNIT_ASSERT(arc2->OpenEntry(*j->second));
|
|
|
|
|
|
|
|
// get pointers to the expected data
|
|
|
|
TestEntries::iterator k;
|
|
|
|
CPPUNIT_ASSERT((k = m_testEntries.find(name)) != m_testEntries.end());
|
|
|
|
TestEntry *entry = k->second;
|
|
|
|
CPPUNIT_ASSERT((k = m_testEntries.find(name2)) != m_testEntries.end());
|
|
|
|
TestEntry *entry2 = k->second;
|
|
|
|
|
|
|
|
size_t count = 0, count2 = 0;
|
|
|
|
size_t size = entry->GetSize(), size2 = entry2->GetSize();
|
|
|
|
const char *data = entry->GetData(), *data2 = entry2->GetData();
|
|
|
|
|
|
|
|
// read and check the two entries in parallel, character by character
|
|
|
|
while (arc->IsOk() || arc2->IsOk()) {
|
|
|
|
char ch = arc->GetC();
|
|
|
|
if (arc->LastRead() == 1) {
|
|
|
|
CPPUNIT_ASSERT(count < size);
|
|
|
|
CPPUNIT_ASSERT(ch == data[count++]);
|
|
|
|
}
|
|
|
|
char ch2 = arc2->GetC();
|
|
|
|
if (arc2->LastRead() == 1) {
|
|
|
|
CPPUNIT_ASSERT(count2 < size2);
|
|
|
|
CPPUNIT_ASSERT(ch2 == data2[count2++]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CPPUNIT_ASSERT(arc->Eof());
|
|
|
|
CPPUNIT_ASSERT(arc2->Eof());
|
|
|
|
CPPUNIT_ASSERT(count == size);
|
|
|
|
CPPUNIT_ASSERT(count2 == size2);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Nothing useful can be done with a generic notifier yet, so just test one
|
|
|
|
// can be set
|
|
|
|
//
|
|
|
|
template <class NotifierT, class EntryT>
|
|
|
|
class ArchiveNotifier : public NotifierT
|
|
|
|
{
|
|
|
|
public:
|
2018-09-21 13:46:49 -04:00
|
|
|
void OnEntryUpdated(EntryT& WXUNUSED(entry)) wxOVERRIDE { }
|
2004-11-10 18:58:38 -05:00
|
|
|
};
|
|
|
|
|
2005-02-10 09:06:08 -05:00
|
|
|
template <class ClassFactoryT>
|
|
|
|
void ArchiveTestCase<ClassFactoryT>::OnSetNotifier(EntryT& entry)
|
2004-11-10 18:58:38 -05:00
|
|
|
{
|
|
|
|
static ArchiveNotifier<NotifierT, EntryT> notifier;
|
|
|
|
entry.SetNotifier(notifier);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-09-24 07:52:53 -04:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// An additional case to check that reading corrupt archives doesn't crash
|
|
|
|
|
|
|
|
class CorruptionTestCase : public CppUnit::TestCase
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
CorruptionTestCase(std::string name,
|
|
|
|
wxArchiveClassFactory *factory,
|
|
|
|
int options)
|
|
|
|
: CppUnit::TestCase(TestId::MakeId() + name),
|
|
|
|
m_factory(factory),
|
|
|
|
m_options(options)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
// the entry point for the test
|
2017-11-07 07:50:47 -05:00
|
|
|
void runTest() wxOVERRIDE;
|
2006-09-24 07:52:53 -04:00
|
|
|
|
2017-11-07 07:50:47 -05:00
|
|
|
protected:
|
2006-09-24 07:52:53 -04:00
|
|
|
void CreateArchive(wxOutputStream& out);
|
|
|
|
void ExtractArchive(wxInputStream& in);
|
|
|
|
|
2016-02-13 07:36:58 -05:00
|
|
|
wxScopedPtr<wxArchiveClassFactory> m_factory; // factory to make classes
|
2006-09-24 07:52:53 -04:00
|
|
|
int m_options; // test options
|
|
|
|
};
|
|
|
|
|
|
|
|
void CorruptionTestCase::runTest()
|
|
|
|
{
|
|
|
|
TestOutputStream out(m_options);
|
|
|
|
CreateArchive(out);
|
|
|
|
TestInputStream in(out, 0);
|
|
|
|
wxFileOffset len = in.GetLength();
|
|
|
|
|
|
|
|
// try flipping one byte in the archive
|
2008-01-12 20:13:03 -05:00
|
|
|
int pos;
|
|
|
|
for (pos = 0; pos < len; pos++) {
|
2006-09-24 07:52:53 -04:00
|
|
|
char n = in[pos];
|
|
|
|
in[pos] = ~n;
|
|
|
|
ExtractArchive(in);
|
|
|
|
in.Rewind();
|
|
|
|
in[pos] = n;
|
|
|
|
}
|
|
|
|
|
|
|
|
// try zeroing one byte in the archive
|
2008-01-12 20:13:03 -05:00
|
|
|
for (pos = 0; pos < len; pos++) {
|
2006-09-24 07:52:53 -04:00
|
|
|
char n = in[pos];
|
|
|
|
in[pos] = 0;
|
|
|
|
ExtractArchive(in);
|
|
|
|
in.Rewind();
|
|
|
|
in[pos] = n;
|
|
|
|
}
|
|
|
|
|
|
|
|
// try chopping the archive off
|
|
|
|
for (int size = 1; size <= len; size++) {
|
|
|
|
in.Chop(size);
|
|
|
|
ExtractArchive(in);
|
|
|
|
in.Rewind();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CorruptionTestCase::CreateArchive(wxOutputStream& out)
|
|
|
|
{
|
2016-02-13 07:36:58 -05:00
|
|
|
wxScopedPtr<wxArchiveOutputStream> arc(m_factory->NewStream(out));
|
2006-09-24 07:52:53 -04:00
|
|
|
|
2009-07-23 16:30:22 -04:00
|
|
|
arc->PutNextDirEntry(wxT("dir"));
|
|
|
|
arc->PutNextEntry(wxT("file"));
|
|
|
|
arc->Write(wxT("foo"), 3);
|
2006-09-24 07:52:53 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void CorruptionTestCase::ExtractArchive(wxInputStream& in)
|
|
|
|
{
|
2016-02-13 07:36:58 -05:00
|
|
|
wxScopedPtr<wxArchiveInputStream> arc(m_factory->NewStream(in));
|
|
|
|
wxScopedPtr<wxArchiveEntry> entry(arc->GetNextEntry());
|
2008-11-19 04:55:27 -05:00
|
|
|
|
2006-09-24 07:52:53 -04:00
|
|
|
while (entry.get() != NULL) {
|
|
|
|
char buf[1024];
|
2008-11-19 04:55:27 -05:00
|
|
|
|
2006-09-24 07:52:53 -04:00
|
|
|
while (arc->IsOk())
|
|
|
|
arc->Read(buf, sizeof(buf));
|
|
|
|
|
2016-02-13 07:36:58 -05:00
|
|
|
entry.reset(arc->GetNextEntry());
|
2006-09-24 07:52:53 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-12-18 08:58:55 -05:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Make the ids
|
|
|
|
|
|
|
|
int TestId::m_seed = 6219;
|
|
|
|
|
|
|
|
// static
|
|
|
|
string TestId::MakeId()
|
|
|
|
{
|
|
|
|
m_seed = (m_seed * 171) % 30269;
|
2009-07-23 16:30:22 -04:00
|
|
|
return string(wxString::Format(wxT("%-6d"), m_seed).mb_str());
|
2005-12-18 08:58:55 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-11-10 18:58:38 -05:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
2005-02-10 09:06:08 -05:00
|
|
|
// Suite base
|
2004-11-10 18:58:38 -05:00
|
|
|
|
2005-02-10 09:06:08 -05:00
|
|
|
ArchiveTestSuite::ArchiveTestSuite(string name)
|
|
|
|
: CppUnit::TestSuite("archive/" + name),
|
|
|
|
m_name(name.c_str(), *wxConvCurrent)
|
2004-11-10 18:58:38 -05:00
|
|
|
{
|
2009-07-23 16:30:22 -04:00
|
|
|
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(""));
|
2004-11-10 18:58:38 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// add the command for an external archiver to the list, testing for it in
|
|
|
|
// the path first
|
|
|
|
//
|
|
|
|
void ArchiveTestSuite::AddCmd(wxArrayString& cmdlist, const wxString& cmd)
|
|
|
|
{
|
|
|
|
if (IsInPath(cmd))
|
|
|
|
cmdlist.push_back(cmd);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ArchiveTestSuite::IsInPath(const wxString& cmd)
|
|
|
|
{
|
2009-07-23 16:30:22 -04:00
|
|
|
wxString c = cmd.BeforeFirst(wxT(' '));
|
2012-03-04 15:31:42 -05:00
|
|
|
#ifdef __WINDOWS__
|
2009-07-23 16:30:22 -04:00
|
|
|
c += wxT(".exe");
|
2004-11-10 18:58:38 -05:00
|
|
|
#endif
|
|
|
|
return !m_path.FindValidPath(c).empty();
|
|
|
|
}
|
|
|
|
|
2017-11-07 07:50:47 -05:00
|
|
|
// run all the tests in the test suite
|
2004-11-10 18:58:38 -05:00
|
|
|
//
|
2017-11-07 07:50:47 -05:00
|
|
|
void ArchiveTestSuite::DoRunTest()
|
2004-11-10 18:58:38 -05:00
|
|
|
{
|
|
|
|
typedef wxArrayString::iterator Iter;
|
|
|
|
|
2005-02-10 09:06:08 -05:00
|
|
|
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)
|
2004-11-10 18:58:38 -05:00
|
|
|
for (int options = 0; options <= AllOptions; options++)
|
|
|
|
{
|
2005-02-10 09:06:08 -05:00
|
|
|
#ifdef WXARC_NO_POPEN
|
|
|
|
// if no popen then can't pipe in/out of archiver
|
2004-11-10 18:58:38 -05:00
|
|
|
if ((options & PipeIn) && !i->empty())
|
|
|
|
continue;
|
|
|
|
if ((options & PipeOut) && !j->empty())
|
|
|
|
continue;
|
|
|
|
#endif
|
2005-02-10 09:06:08 -05:00
|
|
|
string descr = Description(m_name, options,
|
|
|
|
generic != 0, *j, *i);
|
2004-11-10 18:58:38 -05:00
|
|
|
|
2005-12-18 08:58:55 -05:00
|
|
|
CppUnit::Test *test = makeTest(descr, options,
|
2005-02-10 09:06:08 -05:00
|
|
|
generic != 0, *j, *i);
|
|
|
|
|
2005-12-18 08:58:55 -05:00
|
|
|
if (test)
|
2017-11-07 07:50:47 -05:00
|
|
|
{
|
|
|
|
test->runTest();
|
|
|
|
delete test;
|
|
|
|
}
|
2005-02-10 09:06:08 -05:00
|
|
|
}
|
2004-11-10 18:58:38 -05:00
|
|
|
|
2008-11-19 04:55:27 -05:00
|
|
|
for (int options = 0; options <= PipeIn; options += PipeIn)
|
2006-09-24 07:52:53 -04:00
|
|
|
{
|
2009-07-23 16:30:22 -04:00
|
|
|
wxObject *pObj = wxCreateDynamicObject(m_name + wxT("ClassFactory"));
|
2006-09-24 07:52:53 -04:00
|
|
|
wxArchiveClassFactory *factory;
|
|
|
|
factory = wxDynamicCast(pObj, wxArchiveClassFactory);
|
|
|
|
|
|
|
|
if (factory) {
|
|
|
|
string descr(m_name.mb_str());
|
|
|
|
descr = "CorruptionTestCase (" + descr + ")";
|
|
|
|
|
|
|
|
if (options)
|
|
|
|
descr += " (PipeIn)";
|
|
|
|
|
2017-11-07 07:50:47 -05:00
|
|
|
CorruptionTestCase test(descr, factory, options);
|
|
|
|
test.runTest();
|
2006-09-24 07:52:53 -04:00
|
|
|
}
|
|
|
|
}
|
2004-11-10 18:58:38 -05:00
|
|
|
}
|
|
|
|
|
2005-02-10 09:06:08 -05:00
|
|
|
CppUnit::Test *ArchiveTestSuite::makeTest(
|
|
|
|
string WXUNUSED(descr),
|
|
|
|
int WXUNUSED(options),
|
|
|
|
bool WXUNUSED(genericInterface),
|
|
|
|
const wxString& WXUNUSED(archiver),
|
|
|
|
const wxString& WXUNUSED(unarchiver))
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2004-11-10 18:58:38 -05:00
|
|
|
// make a display string for the option bits
|
|
|
|
//
|
2004-11-23 08:49:43 -05:00
|
|
|
string ArchiveTestSuite::Description(const wxString& type,
|
|
|
|
int options,
|
|
|
|
bool genericInterface,
|
|
|
|
const wxString& archiver,
|
|
|
|
const wxString& unarchiver)
|
2004-11-10 18:58:38 -05:00
|
|
|
{
|
|
|
|
wxString descr;
|
2005-01-18 14:50:43 -05:00
|
|
|
|
2004-11-10 18:58:38 -05:00
|
|
|
if (genericInterface)
|
2009-07-23 16:30:22 -04:00
|
|
|
descr << wxT("wxArchive (") << type << wxT(")");
|
2004-11-10 18:58:38 -05:00
|
|
|
else
|
|
|
|
descr << type;
|
|
|
|
|
2005-02-10 09:06:08 -05:00
|
|
|
if (!archiver.empty()) {
|
2009-07-23 16:30:22 -04:00
|
|
|
const wxChar *fn = (options & PipeOut) != 0 ? wxT("-") : wxT("file");
|
2010-06-24 06:33:36 -04:00
|
|
|
const wxString cmd = archiver.Contains("%s")
|
|
|
|
? wxString::Format(archiver, fn)
|
|
|
|
: archiver;
|
|
|
|
descr << wxT(" (") << cmd << wxT(")");
|
2005-02-10 09:06:08 -05:00
|
|
|
}
|
|
|
|
if (!unarchiver.empty()) {
|
2009-07-23 16:30:22 -04:00
|
|
|
const wxChar *fn = (options & PipeIn) != 0 ? wxT("-") : wxT("file");
|
2010-06-24 06:33:36 -04:00
|
|
|
const wxString cmd = unarchiver.Contains("%s")
|
|
|
|
? wxString::Format(unarchiver, fn)
|
|
|
|
: unarchiver;
|
|
|
|
descr << wxT(" (") << cmd << wxT(")");
|
2005-02-10 09:06:08 -05:00
|
|
|
}
|
2005-01-18 14:50:43 -05:00
|
|
|
|
2004-11-10 18:58:38 -05:00
|
|
|
wxString optstr;
|
|
|
|
|
|
|
|
if ((options & PipeIn) != 0)
|
2009-07-23 16:30:22 -04:00
|
|
|
optstr += wxT("|PipeIn");
|
2004-11-10 18:58:38 -05:00
|
|
|
if ((options & PipeOut) != 0)
|
2009-07-23 16:30:22 -04:00
|
|
|
optstr += wxT("|PipeOut");
|
2004-11-10 18:58:38 -05:00
|
|
|
if ((options & Stub) != 0)
|
2009-07-23 16:30:22 -04:00
|
|
|
optstr += wxT("|Stub");
|
2004-11-10 18:58:38 -05:00
|
|
|
if (!optstr.empty())
|
2009-07-23 16:30:22 -04:00
|
|
|
optstr = wxT(" (") + optstr.substr(1) + wxT(")");
|
2004-11-10 18:58:38 -05:00
|
|
|
|
|
|
|
descr << optstr;
|
|
|
|
|
2006-09-24 07:52:53 -04:00
|
|
|
return string(descr.mb_str());
|
2004-11-10 18:58:38 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-02-10 09:06:08 -05:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Instantiations
|
|
|
|
|
|
|
|
template class ArchiveTestCase<wxArchiveClassFactory>;
|
|
|
|
|
|
|
|
#if wxUSE_ZIPSTREAM
|
|
|
|
#include "wx/zipstrm.h"
|
|
|
|
template class ArchiveTestCase<wxZipClassFactory>;
|
|
|
|
#endif
|
2004-11-10 18:58:38 -05:00
|
|
|
|
2006-10-27 06:11:46 -04:00
|
|
|
#if wxUSE_TARSTREAM
|
|
|
|
#include "wx/tarstrm.h"
|
|
|
|
template class ArchiveTestCase<wxTarClassFactory>;
|
|
|
|
#endif
|
|
|
|
|
2005-02-12 16:40:48 -05:00
|
|
|
#endif // wxUSE_STREAMS && wxUSE_ARCHIVE_STREAMS
|