LCOV - code coverage report
Current view: top level - tests - catch_directory_helper.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 72 80 90.0 %
Date: 2024-06-15 08:26:09 Functions: 9 9 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-2022  Made to Order Software Corp.  All Rights Reserved
       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 "catch_main.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       11198 : file_t::file_t(type_t t, int children_count, std::string const& new_filename)
      77       11198 :     : m_filename(new_filename) // see below also
      78       11198 :     , m_children() // see below
      79       11198 :     , m_type(t)
      80             : {
      81             :     // generate a random filename
      82       11198 :     if(m_filename.empty())
      83             :     {
      84             :         for(;;)
      85             :         {
      86       11171 :             size_t const l(rand() % 100 + 1);
      87      578129 :             for(size_t idx(0); idx < l; ++idx)
      88             :             {
      89      566958 :                 m_filename += g_letters[rand() % sizeof(g_letters)];
      90             :             }
      91             :             struct stat buf;
      92       11171 :             if(m_filename != "inexistant" // very unlikely, but just in case...
      93       11171 :             && stat(m_filename.c_str(), &buf) != 0)
      94             :             {
      95             :                 // file does not exist, return safely
      96       11168 :                 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       11198 :     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       10032 :         std::ofstream os(m_filename, std::ios::out | std::ios::binary);
     112       10032 :         size_t count(rand() % (100 * 1024 + 1)); // 0 to 100Kb
     113   513876603 :         for(size_t sz(0); sz < count; ++sz)
     114             :         {
     115   513866571 :             os << static_cast<unsigned char>(rand());
     116             :         }
     117       10032 :         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       10032 :     }
     123        1166 :     else if(t == type_t::DIRECTORY)
     124             :     {
     125        1166 :         if(mkdir(m_filename.c_str(), 0777) != 0)
     126             :         {
     127             :             throw std::runtime_error("failed creating directory"); // LCOV_EXCL_LINE
     128             :         }
     129        1166 :         CATCH_REQUIRE(chdir(m_filename.c_str()) == 0);
     130       12334 :         for(int i(0); i < children_count; ++i)
     131             :         {
     132             :             try
     133             :             {
     134       11168 :                 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 :                 CATCH_REQUIRE(chdir("..") == 0);
     140           0 :                 rmdir(m_filename.c_str());
     141           0 :                 throw;
     142           0 :             }
     143             :         }
     144        1166 :         CATCH_REQUIRE(chdir("..") == 0);
     145             :     }
     146             :     else
     147             :     {
     148             :         throw std::logic_error("unknown type of file"); // LCOV_EXCL_LINE
     149             :     }
     150       11198 : }
     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       11198 : file_t::~file_t()
     161             : {
     162             : // use this return to keep the tree to check files before they get deleted
     163             : //return;
     164       11198 :     if(m_type == type_t::REGULAR)
     165             :     {
     166       10032 :         unlink(m_filename.c_str());
     167             :     }
     168        1166 :     else if(m_type == type_t::DIRECTORY)
     169             :     {
     170             :         // make sure to delete all the children first
     171        1166 :         chdir(m_filename.c_str());
     172        1166 :         m_children.clear();
     173        1166 :         chdir("..");
     174        1166 :         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       11198 : }
     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       89870 : file_t::type_t file_t::type() const
     193             : {
     194       89870 :     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       10208 : std::string const& file_t::filename() const
     212             : {
     213       10208 :     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       88225 : size_t file_t::size()
     244             : {
     245       88225 :     size_t sz(1); // start with self
     246      176287 :     for(size_t idx(0); idx < m_children.size(); ++idx)
     247             :     {
     248       88062 :         sz += m_children[idx]->size();
     249             :     }
     250       88225 :     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     5482303 : file_t::type_t file_t::find(std::string const & name)
     264             : {
     265     5482303 :     std::string::size_type const pos(name.find('/'));
     266             : 
     267     5482303 :     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     5482303 :     if(segment != m_filename)
     272             :     {
     273             :         // not a match...
     274     5178321 :         return type_t::UNKNOWN;
     275             :     }
     276             : 
     277      303982 :     if(pos == std::string::npos)
     278             :     {
     279             :         // end of 'name' so we got a match
     280       89231 :         return type();
     281             :     }
     282             : 
     283      214751 :     std::string const remainder(name.substr(pos + 1));
     284             : 
     285             :     // this was a folder name, search for child
     286     5393072 :     for(auto it(m_children.begin()); it != m_children.end(); ++it)
     287             :     {
     288     5393072 :         type_t t((*it)->find(remainder));
     289     5393072 :         if(t != type_t::UNKNOWN)
     290             :         {
     291      214751 :             return t;
     292             :         }
     293             :     }
     294             : 
     295           0 :     return type_t::UNKNOWN;
     296     5482303 : }
     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           0 : }
     311             : 
     312        7317 : void file_t::get_filenames(filenames_t& names, std::string const& parent) const
     313             : {
     314        7317 :     if(m_type == type_t::DIRECTORY)
     315             :     {
     316             :         // mark directories as such
     317         762 :         names.push_back(parent + "/");
     318             :     }
     319             :     else
     320             :     {
     321        6555 :         names.push_back(parent);
     322             :     }
     323       14614 :     for(auto it(m_children.begin()); it != m_children.end(); ++it)
     324             :     {
     325        7297 :         file_t::pointer_t f(*it);
     326        7297 :         std::string p(parent + "/" + f->filename());
     327        7297 :         f->get_filenames(names, p);
     328        7297 :     }
     329        7317 : }
     330             : 
     331             : 
     332             : } // 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.14

Snap C++ | List of projects | List of versions