LCOV - code coverage report
Current view: top level - tests - directory_helper.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 69 75 92.0 %
Date: 2019-04-24 14:10:30 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-2019  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.1 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
      20             : */
      21             : 
      22             : /** \file
      23             :  *
      24             :  * Zipios unit tests for the DirectoryCollection class.
      25             :  */
      26             : 
      27             : #include "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       10523 : 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       10523 :     , m_type(t)
      80             : {
      81             :     // generate a random filename
      82       10523 :     if(m_filename.empty())
      83             :     {
      84           2 :         for(;;)
      85             :         {
      86       10495 :             size_t const l(rand() % 100 + 1);
      87      544041 :             for(size_t idx(0); idx < l; ++idx)
      88             :             {
      89      533546 :                 m_filename += g_letters[rand() % sizeof(g_letters)];
      90             :             }
      91             :             struct stat buf;
      92       20990 :             if(m_filename != "inexistant" // very unlikely, but just in case...
      93       10495 :             && stat(m_filename.c_str(), &buf) != 0)
      94             :             {
      95             :                 // file does not exist, return safely
      96       10493 :                 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       10523 :     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       18958 :         std::ofstream os(m_filename, std::ios::out | std::ios::binary);
     112        9479 :         size_t count(rand() % (100 * 1024 + 1)); // 0 to 100Kb
     113   486602464 :         for(size_t sz(0); sz < count; ++sz)
     114             :         {
     115   486592985 :             os << static_cast<unsigned char>(rand());
     116             :         }
     117        9479 :         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             :         }
     122             :     }
     123        1044 :     else if(t == type_t::DIRECTORY)
     124             :     {
     125        1044 :         if(mkdir(m_filename.c_str(), 0777) != 0)
     126             :         {
     127             :             throw std::runtime_error("failed creating directory"); // LCOV_EXCL_LINE
     128             :         }
     129        1044 :         chdir(m_filename.c_str());
     130       11537 :         for(int i(0); i < children_count; ++i)
     131             :         {
     132             :             try
     133             :             {
     134       10493 :                 m_children.push_back(pointer_t(new file_t(rand() % 10 == 0 ? type_t::DIRECTORY : type_t::REGULAR, children_count / 3)));
     135             :             }
     136           0 :             catch(...)
     137             :             {
     138           0 :                 m_children.clear();
     139           0 :                 chdir("..");
     140           0 :                 rmdir(m_filename.c_str());
     141           0 :                 throw;
     142             :             }
     143             :         }
     144        1044 :         chdir("..");
     145             :     }
     146             :     else
     147             :     {
     148             :         throw std::logic_error("unknown type of file"); // LCOV_EXCL_LINE
     149             :     }
     150       10523 : }
     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       21046 : file_t::~file_t()
     161             : {
     162             : // use this return to keep the tree to check files before they get deleted
     163             : //return;
     164       10523 :     if(m_type == type_t::REGULAR)
     165             :     {
     166        9479 :         unlink(m_filename.c_str());
     167             :     }
     168        1044 :     else if(m_type == type_t::DIRECTORY)
     169             :     {
     170             :         // make sure to delete all the children first
     171        1044 :         chdir(m_filename.c_str());
     172        1044 :         m_children.clear();
     173        1044 :         chdir("..");
     174        1044 :         rmdir(m_filename.c_str());
     175             :     }
     176             :     else
     177             :     {
     178             :         // we cannot throw in a destructor... (g++ 7.0+ detects that now!)
     179             :         //throw std::logic_error("unknown type of file"); // LCOV_EXCL_LINE
     180             :         std::cerr << "fatal error: unknown type of file" << std::endl; // LCOV_EXCL_LINE
     181             :         std::terminate(); // LCOV_EXCL_LINE
     182             :     }
     183       10523 : }
     184             : 
     185             : /** \brief Retrieve the type of this file_t object.
     186             :  *
     187             :  * This function tells you whether this file_t object is a regular
     188             :  * file or a directory.
     189             :  *
     190             :  * \return REGULAR or DIRECTORY.
     191             :  */
     192      133407 : file_t::type_t file_t::type() const
     193             : {
     194      133407 :     return m_type;
     195             : }
     196             : 
     197             : /** \brief Return the filename.
     198             :  *
     199             :  * This function returns the filename of the file_t object.
     200             :  *
     201             :  * Since most filenames are generated, it is imperative to have a
     202             :  * way to retrieve the filename of a file_t.
     203             :  *
     204             :  * \note
     205             :  * Filenames are ASCII only (0-9, a-z, A-Z, and a few other characters.)
     206             :  *
     207             :  * \return The filename as a standard string.
     208             :  *
     209             :  * \sa g_letters
     210             :  */
     211        8516 : std::string const& file_t::filename() const
     212             : {
     213        8516 :     return m_filename;
     214             : }
     215             : 
     216             : /** \brief Retrieve the children of this file_t object.
     217             :  *
     218             :  * This function retrieves a vector of children. If the file is
     219             :  * a REGULAR file, then the list of children is always empty.
     220             :  *
     221             :  * To get the size of a certain directory, use children().size().
     222             :  */
     223          30 : file_t::vector_t const& file_t::children() const
     224             : {
     225          30 :     return m_children;
     226             : }
     227             : 
     228             : /** \brief Calculate the size of the tree starting at this file.
     229             :  *
     230             :  * This function is the total number of files this item represents,
     231             :  * including itself.
     232             :  *
     233             :  * The zip includes the directories since these are expected to
     234             :  * appear in the final Zip archive.
     235             :  *
     236             :  * \warning
     237             :  * This function returns a count that includes the root directory.
     238             :  * In other words, you have to use the result minus one to compare
     239             :  * with the total count of a DirectoryCollection.
     240             :  *
     241             :  * \return The total size.
     242             :  */
     243      132094 : size_t file_t::size()
     244             : {
     245      132094 :     size_t sz(1); // start with self
     246      264025 :     for(size_t idx(0); idx < m_children.size(); ++idx)
     247             :     {
     248      131931 :         sz += m_children[idx]->size();
     249             :     }
     250      132094 :     return sz;
     251             : }
     252             : 
     253             : /** \brief Search a file in the tree.
     254             :  *
     255             :  * This function is used to search for a file in the tree. It is
     256             :  * rather slow, that being said, it is used to verify that we get
     257             :  * exactly the same list in the DirectoryCollection.
     258             :  *
     259             :  * \param[in] name  The fullname of the file to search.
     260             :  *
     261             :  * \return true if the file is found, false otherwise.
     262             :  */
     263    10479004 : file_t::type_t file_t::find(std::string const& name)
     264             : {
     265    10479004 :     std::string::size_type const pos(name.find('/'));
     266             : 
     267    20958008 :     std::string const segment(pos == std::string::npos ? name : name.substr(0, pos));
     268             : 
     269             : //std::cerr << "segment = [" << segment << "] vs filename [" << m_filename << "]\n";
     270             : 
     271    10479004 :     if(segment != m_filename)
     272             :     {
     273             :         // not a match...
     274    10005545 :         return type_t::UNKNOWN;
     275             :     }
     276             : 
     277      473459 :     if(pos == std::string::npos)
     278             :     {
     279             :         // end of 'name' so we got a match
     280      132846 :         return type();
     281             :     }
     282             : 
     283      681226 :     std::string const remainder(name.substr(pos + 1));
     284             : 
     285             :     // this was a folder name, search for child
     286    10346158 :     for(auto it(m_children.begin()); it != m_children.end(); ++it)
     287             :     {
     288    10346158 :         type_t t((*it)->find(remainder));
     289    10346158 :         if(t != type_t::UNKNOWN)
     290             :         {
     291      340613 :             return t;
     292             :         }
     293             :     }
     294             : 
     295           0 :     return type_t::UNKNOWN;
     296             : }
     297             : 
     298             : /** \brief Retrieve all the filenames.
     299             :  *
     300             :  * This function builds a vector of all the filenames defined in this
     301             :  * tree. The sub-folders get their path added as expected.
     302             :  *
     303             :  * \return An array with all the filenames defined in this tree.
     304             :  */
     305          20 : file_t::filenames_t file_t::get_all_filenames() const
     306             : {
     307          20 :     filenames_t names;
     308          20 :     get_filenames(names, m_filename);
     309          20 :     return names;
     310             : }
     311             : 
     312        6027 : void file_t::get_filenames(filenames_t& names, std::string const& parent) const
     313             : {
     314        6027 :     if(m_type == type_t::DIRECTORY)
     315             :     {
     316             :         // mark directories as such
     317         626 :         names.push_back(parent + "/");
     318             :     }
     319             :     else
     320             :     {
     321        5401 :         names.push_back(parent);
     322             :     }
     323       12034 :     for(auto it(m_children.begin()); it != m_children.end(); ++it)
     324             :     {
     325       12014 :         file_t::pointer_t f(*it);
     326       12014 :         std::string p(parent + "/" + f->filename());
     327        6007 :         f->get_filenames(names, p);
     328             :     }
     329        6027 : }
     330             : 
     331             : 
     332           3 : } // zipios_tests namespace
     333             : 
     334             : // Local Variables:
     335             : // mode: cpp
     336             : // indent-tabs-mode: nil
     337             : // c-basic-offset: 4
     338             : // tab-width: 4
     339             : // End:
     340             : 
     341             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.12