// Name: tests/archive/archive.cpp
// Purpose: Test the archive classes
// Author: Mike Wetherell
-// RCS-ID: $Id$
// Copyright: (c) 2004 Mike Wetherell
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
#if defined __DMC__ && __DMC__ >= 0x832
# define WXARC_MEMBER_TEMPLATES
#endif
-#if defined __MWERKS__ && __MWERKS__ >= 0x2200
-# define WXARC_MEMBER_TEMPLATES
-#endif
#if defined __HP_aCC && __HP_aCC > 33300
# define WXARC_MEMBER_TEMPLATES
#endif
m_wbacksize = 0;
m_wbackcur = 0;
}
+
+ Reset();
}
void TestInputStream::SetData(TestOutputStream& out)
m_options = out.GetOptions();
out.GetData(m_data, m_size);
Rewind();
- Reset();
}
wxFileOffset TestInputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode)
}
if (((m_eoftype & AtLast) != 0 && m_pos >= m_size) || count < size)
+ {
if ((m_eoftype & WithError) != 0)
m_lasterror = wxSTREAM_READ_ERROR;
else
m_lasterror = wxSTREAM_EOF;
+ }
return count;
}
TempDir::TempDir()
{
- wxString tmp = wxFileName::CreateTempFileName(_T("arctest-"));
+ wxString tmp = wxFileName::CreateTempFileName(wxT("arctest-"));
if (!tmp.empty()) {
wxRemoveFile(tmp);
m_original = wxGetCwd();
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();
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());
+ }
}
# define WXARC_pclose(fp)
#endif
-#ifdef __WXMSW__
+#ifdef __WINDOWS__
# define WXARC_b "b"
#else
# define WXARC_b
// 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()) {
testEntry.GetLength()));
}
- if (it->first.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,
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());
wxFileName fn(i->first, wxPATH_UNIX);
TestEntry& entry = *i->second;
wxDateTime dt = entry.GetDateTime();
-#ifdef __WXMSW__
+#ifdef __WINDOWS__
if (fn.IsDir())
entry.SetDateTime(wxDateTime());
else
if ((m_options & PipeOut) == 0) {
wxFileName fn(tmpdir.GetName());
- fn.SetExt(_T("arc"));
+ 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());
+ if ( system(wxString::Format(archiver, tmparc.c_str()).mb_str()) == -1 )
+ {
+ wxLogError("Failed to run acrhiver command \"%s\"", archiver);
+ }
// then load the archive file
{
wxFFileInputStream in(tmparc);
- if (in.Ok())
+ if (in.IsOk())
out.Write(in);
}
else {
// for the non-seekable test, have the archiver output to "-"
// and read the archive via a pipe
- PFileInputStream in(wxString::Format(archiver, _T("-")));
- if (in.Ok())
+ PFileInputStream in(wxString::Format(archiver, wxT("-")));
+ if (in.IsOk())
out.Write(in);
}
}
auto_ptr<OutputStreamT> 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);
// 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) {
// 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);
const TestEntry& testEntry = *it->second;
+#ifndef __WINDOWS__
+ // 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
"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());
if ((m_options & PipeIn) == 0) {
wxFileName fn(tmpdir.GetName());
- fn.SetExt(_T("arc"));
+ fn.SetExt(wxT("arc"));
wxString tmparc = fn.GetPath(wxPATH_GET_SEPARATOR) + fn.GetFullName();
if (m_options & Stub)
// write the archive to a temporary file
{
wxFFileOutputStream out(tmparc);
- if (out.Ok())
+ if (out.IsOk())
out.Write(in);
}
// call unarchiver
- system(wxString::Format(unarchiver, tmparc.c_str()).mb_str());
+ if ( system(wxString::Format(unarchiver, tmparc.c_str()).mb_str()) == -1 )
+ {
+ wxLogError("Failed to run unarchiver command \"%s\"", unarchiver);
+ }
+
wxRemoveFile(tmparc);
}
else {
// for the non-seekable test, have the archiver extract "-" and
// feed it the archive via a pipe
- PFileOutputStream out(wxString::Format(unarchiver, _T("-")));
- if (out.Ok())
+ PFileOutputStream out(wxString::Format(unarchiver, wxT("-")));
+ if (out.IsOk())
out.Write(in);
}
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);
const TestEntry& testEntry = *it->second;
-#if 0 //ndef __WXMSW__
+#if 0 //ndef __WINDOWS__
CPPUNIT_ASSERT_MESSAGE("timestamp check" + error_context,
testEntry.GetDateTime() ==
wxFileName(path).GetModificationTime());
if (!isDir) {
wxFFileInputStream in(path);
CPPUNIT_ASSERT_MESSAGE(
- "entry not found in archive" + error_entry, in.Ok());
+ "entry not found in archive" + error_entry, in.IsOk());
size_t size = (size_t)in.GetLength();
wxCharBuffer buf(size);
#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;
}
+///////////////////////////////////////////////////////////////////////////////
+// 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)
+ { }
+
+protected:
+ // the entry point for the test
+ void runTest();
+
+ void CreateArchive(wxOutputStream& out);
+ void ExtractArchive(wxInputStream& in);
+
+ auto_ptr<wxArchiveClassFactory> m_factory; // factory to make classes
+ 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
+ int pos;
+ for (pos = 0; pos < len; pos++) {
+ char n = in[pos];
+ in[pos] = ~n;
+ ExtractArchive(in);
+ in.Rewind();
+ in[pos] = n;
+ }
+
+ // 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;
+ }
+
+ // try chopping the archive off
+ for (int size = 1; size <= len; size++) {
+ in.Chop(size);
+ ExtractArchive(in);
+ in.Rewind();
+ }
+}
+
+void CorruptionTestCase::CreateArchive(wxOutputStream& out)
+{
+ auto_ptr<wxArchiveOutputStream> arc(m_factory->NewStream(out));
+
+ arc->PutNextDirEntry(wxT("dir"));
+ arc->PutNextEntry(wxT("file"));
+ arc->Write(wxT("foo"), 3);
+}
+
+void CorruptionTestCase::ExtractArchive(wxInputStream& in)
+{
+ auto_ptr<wxArchiveInputStream> arc(m_factory->NewStream(in));
+ auto_ptr<wxArchiveEntry> entry(arc->GetNextEntry());
+
+ while (entry.get() != NULL) {
+ char buf[1024];
+
+ while (arc->IsOk())
+ arc->Read(buf, sizeof(buf));
+
+ auto_ptr<wxArchiveEntry> next(arc->GetNextEntry());
+ entry = next;
+ }
+}
+
+
///////////////////////////////////////////////////////////////////////////////
// Make the ids
string TestId::MakeId()
{
m_seed = (m_seed * 171) % 30269;
- return (const char *)wxString::Format(_T("%-6d"), m_seed).mb_str();
+ return string(wxString::Format(wxT("%-6d"), m_seed).mb_str());
}
: CppUnit::TestSuite("archive/" + name),
m_name(name.c_str(), *wxConvCurrent)
{
- m_name = _T("wx") + m_name.Left(1).Upper() + m_name.Mid(1).Lower();
- m_path.AddEnvList(_T("PATH"));
- m_archivers.push_back(_T(""));
- m_unarchivers.push_back(_T(""));
+ 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
bool ArchiveTestSuite::IsInPath(const wxString& cmd)
{
- wxString c = cmd.BeforeFirst(_T(' '));
-#ifdef __WXMSW__
- c += _T(".exe");
+ wxString c = cmd.BeforeFirst(wxT(' '));
+#ifdef __WINDOWS__
+ c += wxT(".exe");
#endif
return !m_path.FindValidPath(c).empty();
}
addTest(test);
}
+ 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));
+ }
+ }
+
return this;
}
wxString descr;
if (genericInterface)
- descr << _T("wxArchive (") << type << _T(")");
+ descr << wxT("wxArchive (") << type << wxT(")");
else
descr << type;
if (!archiver.empty()) {
- const wxChar *fn = (options & PipeOut) != 0 ? _T("-") : _T("file");
- descr << _T(" (") << wxString::Format(archiver, fn) << _T(")");
+ const wxChar *fn = (options & PipeOut) != 0 ? wxT("-") : wxT("file");
+ const wxString cmd = archiver.Contains("%s")
+ ? wxString::Format(archiver, fn)
+ : archiver;
+ descr << wxT(" (") << cmd << wxT(")");
}
if (!unarchiver.empty()) {
- const wxChar *fn = (options & PipeIn) != 0 ? _T("-") : _T("file");
- descr << _T(" (") << wxString::Format(unarchiver, fn) << _T(")");
+ const wxChar *fn = (options & PipeIn) != 0 ? wxT("-") : wxT("file");
+ const wxString cmd = unarchiver.Contains("%s")
+ ? wxString::Format(unarchiver, fn)
+ : unarchiver;
+ descr << wxT(" (") << cmd << 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());
}
template class ArchiveTestCase<wxZipClassFactory>;
#endif
+#if wxUSE_TARSTREAM
+#include "wx/tarstrm.h"
+template class ArchiveTestCase<wxTarClassFactory>;
+#endif
+
#endif // wxUSE_STREAMS && wxUSE_ARCHIVE_STREAMS