]> git.saurik.com Git - wxWidgets.git/blobdiff - tests/archive/archivetest.cpp
Convert wxFSW_EVENT_{WARNING,ERROR} to string correctly.
[wxWidgets.git] / tests / archive / archivetest.cpp
index 1e09053104273ed24fe4f69f7b755864da8a4a68..7e8262d0f8e878d32a2b2efc3899122e8a00ed62 100644 (file)
@@ -42,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
@@ -51,9 +51,6 @@ using std::auto_ptr;
 #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
@@ -196,7 +193,8 @@ TestInputStream::TestInputStream(const TestInputStream& in)
   : 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)
 {
     m_data = new char[m_size];
     memcpy(m_data, in.m_data, m_size);
@@ -215,6 +213,8 @@ void TestInputStream::Rewind()
         m_wbacksize = 0;
         m_wbackcur = 0;
     }
+
+    Reset();
 }
 
 void TestInputStream::SetData(TestOutputStream& out)
@@ -223,7 +223,6 @@ void TestInputStream::SetData(TestOutputStream& out)
     m_options = out.GetOptions();
     out.GetData(m_data, m_size);
     Rewind();
-    Reset();
 }
 
 wxFileOffset TestInputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode)
@@ -251,16 +250,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;
 }
 
 
@@ -319,7 +332,7 @@ private:
 
 TempDir::TempDir()
 {
-    wxString tmp = wxFileName::CreateTempFileName(_T("arctest-"));
+    wxString tmp = wxFileName::CreateTempFileName(wxT("arctest-"));
     if (!tmp.empty()) {
         wxRemoveFile(tmp);
         m_original = wxGetCwd();
@@ -340,26 +353,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();
@@ -372,7 +385,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());
+    }
 }
 
 
@@ -391,7 +406,7 @@ void TempDir::RemoveDir(wxString& path)
 #   define WXARC_pclose(fp)
 #endif
 
-#ifdef __WXMSW__
+#ifdef __WINDOWS__
 #   define WXARC_b "b"
 #else
 #   define WXARC_b
@@ -424,17 +439,16 @@ PFileOutputStream::~PFileOutputStream()
 template <class ClassFactoryT>
 ArchiveTestCase<ClassFactoryT>::ArchiveTestCase(
     string name,
-    int id,
     ClassFactoryT *factory,
     int options,
     const wxString& archiver,
     const wxString& unarchiver)
   :
-    CppUnit::TestCase(name),
+    CppUnit::TestCase(TestId::MakeId() + name),
     m_factory(factory),
     m_options(options),
     m_timeStamp(1, wxDateTime::Mar, 2004, 12, 0),
-    m_id(id),
+    m_id(TestId::GetId()),
     m_archiver(archiver),
     m_unarchiver(unarchiver)
 {
@@ -464,7 +478,7 @@ void ArchiveTestCase<ClassFactoryT>::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();
@@ -563,13 +577,13 @@ void ArchiveTestCase<ClassFactoryT>::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()) {
@@ -596,7 +610,7 @@ void ArchiveTestCase<ClassFactoryT>::CreateArchive(wxOutputStream& out)
                                       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,
@@ -632,7 +646,7 @@ void ArchiveTestCase<ClassFactoryT>::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());
@@ -644,7 +658,7 @@ void ArchiveTestCase<ClassFactoryT>::CreateArchive(wxOutputStream& out,
         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
@@ -654,16 +668,19 @@ void ArchiveTestCase<ClassFactoryT>::CreateArchive(wxOutputStream& out,
 
     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);
         }
 
@@ -672,8 +689,8 @@ void ArchiveTestCase<ClassFactoryT>::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("-")));
-        if (in.Ok())
+        PFileInputStream in(wxString::Format(archiver, wxT("-")));
+        if (in.IsOk())
             out.Write(in);
     }
 }
@@ -689,10 +706,10 @@ void ArchiveTestCase<ClassFactoryT>::ModifyArchive(wxInputStream& 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);
@@ -704,7 +721,7 @@ void ArchiveTestCase<ClassFactoryT>::ModifyArchive(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);
 
         if (name == deleteName) {
@@ -779,7 +796,7 @@ void ArchiveTestCase<ClassFactoryT>::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);
@@ -789,10 +806,14 @@ void ArchiveTestCase<ClassFactoryT>::ExtractArchive(wxInputStream& in)
 
         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
@@ -803,7 +824,7 @@ void ArchiveTestCase<ClassFactoryT>::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());
@@ -863,7 +884,7 @@ void ArchiveTestCase<ClassFactoryT>::ExtractArchive(wxInputStream& in,
 
     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)
@@ -872,19 +893,23 @@ void ArchiveTestCase<ClassFactoryT>::ExtractArchive(wxInputStream& in,
         // 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);
     }
 
@@ -914,11 +939,11 @@ void ArchiveTestCase<ClassFactoryT>::VerifyDir(wxString& path,
 
             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);
@@ -929,7 +954,7 @@ void ArchiveTestCase<ClassFactoryT>::VerifyDir(wxString& path,
 
             const TestEntry& testEntry = *it->second;
 
-#ifndef __WXMSW__
+#if 0 //ndef __WINDOWS__
             CPPUNIT_ASSERT_MESSAGE("timestamp check" + error_context,
                                    testEntry.GetDateTime() ==
                                    wxFileName(path).GetModificationTime());
@@ -937,7 +962,7 @@ void ArchiveTestCase<ClassFactoryT>::VerifyDir(wxString& path,
             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);
@@ -1097,8 +1122,8 @@ void ArchiveTestCase<ClassFactoryT>::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;
@@ -1156,18 +1181,115 @@ void ArchiveTestCase<ClassFactoryT>::OnSetNotifier(EntryT& entry)
 }
 
 
+///////////////////////////////////////////////////////////////////////////////
+// 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
+
+int TestId::m_seed = 6219;
+
+// static
+string TestId::MakeId()
+{
+    m_seed = (m_seed * 171) % 30269;
+    return string(wxString::Format(wxT("%-6d"), m_seed).mb_str());
+}
+
+
 ///////////////////////////////////////////////////////////////////////////////
 // Suite base
 
 ArchiveTestSuite::ArchiveTestSuite(string name)
   : CppUnit::TestSuite("archive/" + name),
-    m_id(0),
     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
@@ -1181,9 +1303,9 @@ void ArchiveTestSuite::AddCmd(wxArrayString& cmdlist, const wxString& cmd)
 
 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();
 }
@@ -1209,21 +1331,35 @@ ArchiveTestSuite *ArchiveTestSuite::makeSuite()
                     string descr = Description(m_name, options,
                                                generic != 0, *j, *i);
 
-                    CppUnit::Test *test = makeTest(descr, m_id, options,
+                    CppUnit::Test *test = makeTest(descr, options,
                                                    generic != 0, *j, *i);
 
-                    if (test) {
+                    if (test)
                         addTest(test);
-                        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));
+        }
+    }
+
     return this;
 }
 
 CppUnit::Test *ArchiveTestSuite::makeTest(
     string WXUNUSED(descr),
-    int WXUNUSED(id),
     int WXUNUSED(options),
     bool WXUNUSED(genericInterface),
     const wxString& WXUNUSED(archiver),
@@ -1241,36 +1377,41 @@ 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()) {
-        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());
 }
 
 
@@ -1284,4 +1425,9 @@ template class ArchiveTestCase<wxArchiveClassFactory>;
 template class ArchiveTestCase<wxZipClassFactory>;
 #endif
 
+#if wxUSE_TARSTREAM
+#include "wx/tarstrm.h"
+template class ArchiveTestCase<wxTarClassFactory>;
+#endif
+
 #endif // wxUSE_STREAMS && wxUSE_ARCHIVE_STREAMS