LCOV - code coverage report
Current view: top level - tests - catch_directory_helper.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 71 71 100.0 %
Date: 2015-04-12 Functions: 11 11 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   Zipios++ - a small C++ library that provides easy access to .zip files.
       3             : 
       4             :   Copyright (C) 2000-2007  Thomas Sondergaard
       5             :   Copyright (C) 2015  Made to Order Software Corporation
       6             : 
       7             :   This library is free software; you can redistribute it and/or
       8             :   modify it under the terms of the GNU Lesser General Public
       9             :   License as published by the Free Software Foundation; either
      10             :   version 2 of the License, or (at your option) any later version.
      11             : 
      12             :   This library is distributed in the hope that it will be useful,
      13             :   but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15             :   Lesser General Public License for more details.
      16             : 
      17             :   You should have received a copy of the GNU Lesser General Public
      18             :   License along with this library; if not, write to the Free Software
      19             :   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
      20             : */
      21             : 
      22             : /** \file
      23             :  *
      24             :  * Zipios++ unit tests for the DirectoryCollection class.
      25             :  */
      26             : 
      27             : #include "catch_tests.hpp"
      28             : 
      29             : #include <fstream>
      30             : //
      31             : #include <unistd.h>
      32             : #include <sys/stat.h>
      33             : 
      34             : 
      35             : namespace zipios_test
      36             : {
      37             : 
      38             : 
      39             : namespace
      40             : {
      41             : 
      42             : 
      43             : char const g_letters[66]{
      44             :     '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 
      45             :     'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 
      46             :     'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 
      47             :     '.', '-', '_', '+'
      48             : };
      49             : 
      50             : 
      51             : } // no name namespace
      52             : 
      53             : 
      54             : /** \class file_t
      55             :  * \brief Class used to build a regular file.
      56             :  *
      57             :  * This file class creates a regular file in a directory.
      58             :  */
      59             : 
      60             : 
      61             : /** \brief Create a file.
      62             :  *
      63             :  * This function creates a file. If the creation fails, then an error
      64             :  * is thrown and the process attempts to clean up all the files
      65             :  * created so far.
      66             :  *
      67             :  * The children parameter is used whenever a DIRECTORY is created.
      68             :  * It determines the number of children that get created inside
      69             :  * that directory. Sub-directories (since the creation is recursive)
      70             :  * are given 1/3rd of that number. Also the function creates a new
      71             :  * sub-directory in about 1 in 10 files it creates.
      72             :  *
      73             :  * \param[in] t  The type of file (REGULAR or DIRECTORY).
      74             :  * \param[in] children_count  The number of children to create.
      75             :  */
      76       15747 : file_t::file_t(type_t t, int children_count, std::string const& new_filename)
      77             :     : m_filename(new_filename) // see below also
      78             :     , m_children() // see below
      79       15747 :     , m_type(t)
      80             : {
      81             :     // generate a random filename
      82       15747 :     if(m_filename.empty())
      83             :     {
      84             :         for(;;)
      85             :         {
      86       15707 :             size_t const l(rand() % 100 + 1);
      87      808295 :             for(size_t idx(0); idx < l; ++idx)
      88             :             {
      89      792588 :                 m_filename += g_letters[rand() % sizeof(g_letters)];
      90             :             }
      91             :             struct stat buf;
      92       31414 :             if(m_filename != "inexistant" // very unlikely, but just in case...
      93       15707 :             && stat(m_filename.c_str(), &buf) != 0)
      94             :             {
      95             :                 // file does not exist, return safely
      96       15701 :                 break;
      97             :             }
      98             :         } // LCOV_EXCL_LINE
      99             :     }
     100             : 
     101             :     // This is only to test the validity of the exception handling
     102             :     //if(children_count < 20)
     103             :     //{
     104             :     //    throw std::logic_error("Ooops!");
     105             :     //}
     106             : 
     107       15747 :     if(t == type_t::REGULAR)
     108             :     {
     109             :         // create a regular file
     110             :         // (the STL is expected to throw if the create fails from the constructor)
     111       14141 :         std::ofstream os(m_filename, std::ios::out | std::ios::binary);
     112       14141 :         size_t count(rand() % (100 * 1024 + 1)); // 0 to 100Kb
     113   723384679 :         for(size_t sz(0); sz < count; ++sz)
     114             :         {
     115   723370538 :             os << static_cast<unsigned char>(rand());
     116             :         }
     117       14141 :         if(!os)
     118             :         {
     119             :             unlink(m_filename.c_str()); // LCOV_EXCL_LINE
     120             :             throw std::runtime_error("failed creating regular file"); // LCOV_EXCL_LINE
     121       14141 :         }
     122             :     }
     123        1606 :     else if(t == type_t::DIRECTORY)
     124             :     {
     125        1606 :         if(mkdir(m_filename.c_str(), 0777) != 0)
     126             :         {
     127             :             throw std::runtime_error("failed creating directory"); // LCOV_EXCL_LINE
     128             :         }
     129        1606 :         chdir(m_filename.c_str());
     130       17307 :         for(int i(0); i < children_count; ++i)
     131             :         {
     132             :             try
     133             :             {
     134       15701 :                 m_children.push_back(pointer_t(new file_t(rand() % 10 == 0 ? type_t::DIRECTORY : type_t::REGULAR, children_count / 3)));
     135             :             }
     136             :             catch(...)
     137             :             {
     138             :                 m_children.clear();
     139             :                 chdir("..");
     140             :                 rmdir(m_filename.c_str());
     141             :                 throw;
     142             :             }
     143             :         }
     144        1606 :         chdir("..");
     145             :     }
     146             :     else
     147             :     {
     148             :         throw std::logic_error("unknown type of file"); // LCOV_EXCL_LINE
     149             :     }
     150       15747 : }
     151             : 
     152             : /** \brief Clean up the file.
     153             :  *
     154             :  * This function ensures that this file or directory gets deleted
     155             :  * before deleting the object from memory.
     156             :  *
     157             :  * This function is recursive. When deleting a directory, all of
     158             :  * its children get deleted first.
     159             :  */
     160       31494 : file_t::~file_t()
     161             : {
     162             : // use this return to keep the tree to check files before they get deleted
     163             : //return;
     164       15747 :     if(m_type == type_t::REGULAR)
     165             :     {
     166       14141 :         unlink(m_filename.c_str());
     167             :     }
     168        1606 :     else if(m_type == type_t::DIRECTORY)
     169             :     {
     170             :         // make sure to delete all the children first
     171        1606 :         chdir(m_filename.c_str());
     172        1606 :         m_children.clear();
     173        1606 :         chdir("..");
     174        1606 :         rmdir(m_filename.c_str());
     175             :     }
     176             :     else
     177             :     {
     178             :         // throw in destructor?!
     179             :         throw std::logic_error("unknown type of file"); // LCOV_EXCL_LINE
     180             :     }
     181       15747 : }
     182             : 
     183             : /** \brief Retrieve the type of this file_t object.
     184             :  *
     185             :  * This function tells you whether this file_t object is a regular
     186             :  * file or a directory.
     187             :  *
     188             :  * \return REGULAR or DIRECTORY.
     189             :  */
     190       92568 : file_t::type_t file_t::type() const
     191             : {
     192       92568 :     return m_type;
     193             : }
     194             : 
     195             : /** \brief Return the filename.
     196             :  *
     197             :  * This function returns the filename of the file_t object.
     198             :  *
     199             :  * Since most filenames are generated, it is imperative to have a
     200             :  * way to retrieve the filename of a file_t.
     201             :  *
     202             :  * \note
     203             :  * Filenames are ASCII only (0-9, a-z, A-Z, and a few other characters.)
     204             :  *
     205             :  * \return The filename as a standard string.
     206             :  *
     207             :  * \sa g_letters
     208             :  */
     209        8516 : std::string const& file_t::filename() const
     210             : {
     211        8516 :     return m_filename;
     212             : }
     213             : 
     214             : /** \brief Retrieve the children of this file_t object.
     215             :  *
     216             :  * This function retrieves a vector of children. If the file is
     217             :  * a REGULAR file, then the list of children is always empty.
     218             :  *
     219             :  * To get the size of a certain directory, use children().size().
     220             :  */
     221          30 : file_t::vector_t const& file_t::children() const
     222             : {
     223          30 :     return m_children;
     224             : }
     225             : 
     226             : /** \brief Calculate the size of the tree starting at this file.
     227             :  *
     228             :  * This function is the total number of files this item represents,
     229             :  * including itself.
     230             :  *
     231             :  * The zip includes the directories since these are expected to
     232             :  * appear in the final Zip archive.
     233             :  *
     234             :  * \warning
     235             :  * This function returns a count that includes the root directory.
     236             :  * In other words, you have to use the result minus one to compare
     237             :  * with the total count of a DirectoryCollection.
     238             :  *
     239             :  * \return The total size.
     240             :  */
     241       91202 : size_t file_t::size()
     242             : {
     243       91202 :     size_t sz(1); // start with self
     244      182227 :     for(size_t idx(0); idx < m_children.size(); ++idx)
     245             :     {
     246       91025 :         sz += m_children[idx]->size();
     247             :     }
     248       91202 :     return sz;
     249             : }
     250             : 
     251             : /** \brief Search a file in the tree.
     252             :  *
     253             :  * This function is used to search for a file in the tree. It is
     254             :  * rather slow, that being said, it is used to verify that we get
     255             :  * exactly the same list in the DirectoryCollection.
     256             :  *
     257             :  * \param[in] name  The fullname of the file to search.
     258             :  *
     259             :  * \return true if the file is found, false otherwise.
     260             :  */
     261     6240872 : file_t::type_t file_t::find(std::string const& name)
     262             : {
     263     6240872 :     std::string::size_type const pos(name.find('/'));
     264             : 
     265     6240872 :     std::string const segment(pos == std::string::npos ? name : name.substr(0, pos));
     266             : 
     267             : //std::cerr << "segment = [" << segment << "] vs filename [" << m_filename << "]\n";
     268             : 
     269     6240872 :     if(segment != m_filename)
     270             :     {
     271             :         // not a match...
     272     5926630 :         return type_t::UNKNOWN;
     273             :     }
     274             : 
     275      314242 :     if(pos == std::string::npos)
     276             :     {
     277             :         // end of 'name' so we got a match
     278       91983 :         return type();
     279             :     }
     280             : 
     281      444518 :     std::string const remainder(name.substr(pos + 1));
     282             : 
     283             :     // this was a folder name, search for child
     284     6148889 :     for(auto it(m_children.begin()); it != m_children.end(); ++it)
     285             :     {
     286     6148889 :         type_t t((*it)->find(remainder));
     287     6148889 :         if(t != type_t::UNKNOWN)
     288             :         {
     289      222259 :             return t;
     290             :         }
     291             :     }
     292             : 
     293     6240872 :     return type_t::UNKNOWN;
     294             : }
     295             : 
     296             : /** \brief Retrieve all the filenames.
     297             :  *
     298             :  * This function builds a vector of all the filenames defined in this
     299             :  * tree. The sub-folders get their path added as expected.
     300             :  *
     301             :  * \return An array with all the filenames defined in this tree.
     302             :  */
     303          20 : file_t::filenames_t file_t::get_all_filenames() const
     304             : {
     305          20 :     filenames_t names;
     306          20 :     get_filenames(names, m_filename);
     307          20 :     return names;
     308             : }
     309             : 
     310        5871 : void file_t::get_filenames(filenames_t& names, std::string const& parent) const
     311             : {
     312        5871 :     if(m_type == type_t::DIRECTORY)
     313             :     {
     314             :         // mark directories as such
     315         603 :         names.push_back(parent + "/");
     316             :     }
     317             :     else
     318             :     {
     319        5268 :         names.push_back(parent);
     320             :     }
     321       11722 :     for(auto it(m_children.begin()); it != m_children.end(); ++it)
     322             :     {
     323        5851 :         file_t::pointer_t f(*it);
     324       11702 :         std::string p(parent + "/" + f->filename());
     325        5851 :         f->get_filenames(names, p);
     326        5851 :     }
     327        5871 : }
     328             : 
     329             : 
     330           3 : } // zipios_tests namespace
     331             : // vim: ts=4 sw=4 et
     332             : 
     333             : // Local Variables:
     334             : // mode: cpp
     335             : // indent-tabs-mode: nil
     336             : // c-basic-offset: 4
     337             : // tab-width: 4
     338             : // End:

Generated by: LCOV version 1.10