LCOV - code coverage report
Current view: top level - tests - catch_virtual_buffer.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 100.0 % 135 135
Test Date: 2025-06-19 11:28:46 Functions: 100.0 % 1 1
Legend: Lines: hit not hit

            Line data    Source code
       1              : // Copyright (c) 2019-2025  Made to Order Software Corp.  All Rights Reserved
       2              : //
       3              : // https://snapwebsites.org/project/prinbee
       4              : // contact@m2osw.com
       5              : //
       6              : // This program is free software: you can redistribute it and/or modify
       7              : // it under the terms of the GNU General Public License as published by
       8              : // the Free Software Foundation, either version 3 of the License, or
       9              : // (at your option) any later version.
      10              : //
      11              : // This program is distributed in the hope that it will be useful,
      12              : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      13              : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14              : // GNU General Public License for more details.
      15              : //
      16              : // You should have received a copy of the GNU General Public License
      17              : // along with this program.  If not, see <https://www.gnu.org/licenses/>.
      18              : 
      19              : // self
      20              : //
      21              : #include    "catch_main.h"
      22              : 
      23              : 
      24              : // prinbee
      25              : //
      26              : #include    <prinbee/data/virtual_buffer.h>
      27              : 
      28              : 
      29              : // advgetopt
      30              : //
      31              : #include    <advgetopt/options.h>
      32              : 
      33              : 
      34              : // last include
      35              : //
      36              : #include    <snapdev/poison.h>
      37              : 
      38              : 
      39              : 
      40            5 : CATCH_TEST_CASE("virtual_buffer", "[virtual-buffer]")
      41              : {
      42            7 :     CATCH_START_SECTION("virtual_buffer: simple write + read")
      43              :     {
      44            1 :         prinbee::virtual_buffer::pointer_t v(std::make_shared<prinbee::virtual_buffer>());
      45            1 :         CATCH_REQUIRE(v->size() == 0);
      46            1 :         CATCH_REQUIRE(v->count_buffers() == 0);
      47              : 
      48            1 :         constexpr std::size_t const buf_size(1024);
      49            1 :         char buf[buf_size];
      50         1025 :         for(std::size_t i(0); i < sizeof(buf); ++i)
      51              :         {
      52         1024 :             buf[i] = rand();
      53              :         }
      54            1 :         CATCH_REQUIRE(v->pwrite(buf, sizeof(buf), 0, true) == sizeof(buf));
      55              : 
      56            1 :         CATCH_REQUIRE(v->size() == sizeof(buf));
      57            1 :         CATCH_REQUIRE(v->count_buffers() == 1);  // one write means at most 1 buffer
      58              : 
      59            1 :         char saved[buf_size];
      60            1 :         CATCH_REQUIRE(v->pread(saved, sizeof(saved), 0, true) == sizeof(saved));
      61              : 
      62            1 :         CATCH_REQUIRE(sizeof(buf) == sizeof(saved));
      63            1 :         CATCH_REQUIRE(memcmp(buf, saved, sizeof(buf)) == 0);
      64            1 :     }
      65            6 :     CATCH_END_SECTION()
      66              : 
      67            7 :     CATCH_START_SECTION("virtual_buffer: write once + read many times")
      68              :     {
      69            1 :         prinbee::virtual_buffer::pointer_t v(std::make_shared<prinbee::virtual_buffer>());
      70            1 :         CATCH_REQUIRE(v->size() == 0);
      71            1 :         CATCH_REQUIRE(v->count_buffers() == 0);
      72              : 
      73            1 :         constexpr size_t const buf_size(1024);
      74            1 :         char buf[buf_size];
      75         1025 :         for(size_t i(0); i < sizeof(buf); ++i)
      76              :         {
      77         1024 :             buf[i] = rand();
      78              :         }
      79            1 :         CATCH_REQUIRE(v->pwrite(buf, sizeof(buf), 0, true) == sizeof(buf));
      80              : 
      81            1 :         CATCH_REQUIRE(v->size() == sizeof(buf));
      82            1 :         CATCH_REQUIRE(v->count_buffers() == 1);  // one write means at most 1 buffer
      83              : 
      84         1025 :         for(size_t i(0); i < sizeof(buf); ++i)
      85              :         {
      86         1024 :             char c;
      87         1024 :             CATCH_REQUIRE(v->pread(&c, sizeof(c), i, true) == sizeof(c));
      88         1024 :             CATCH_REQUIRE(buf[i] == c);
      89              :         }
      90            1 :     }
      91            6 :     CATCH_END_SECTION()
      92              : 
      93            7 :     CATCH_START_SECTION("virtual_buffer: short write + read several times")
      94              :     {
      95            1 :         prinbee::virtual_buffer::pointer_t v(std::make_shared<prinbee::virtual_buffer>());
      96            1 :         CATCH_REQUIRE(v->size() == 0);
      97            1 :         CATCH_REQUIRE(v->count_buffers() == 0);
      98              : 
      99            1 :         constexpr size_t const buf_size(1024);
     100            1 :         char buf[buf_size];
     101         1025 :         for(size_t i(0); i < sizeof(buf); ++i)
     102              :         {
     103         1024 :             buf[i] = rand();
     104              :         }
     105            1 :         CATCH_REQUIRE(v->pwrite(buf, sizeof(buf), 0, true) == sizeof(buf));
     106              : 
     107            1 :         CATCH_REQUIRE(v->size() == sizeof(buf));
     108            1 :         CATCH_REQUIRE(v->count_buffers() == 1);  // one write means at most 1 buffer
     109              : 
     110              :         // update the first 4 bytes
     111              :         //
     112            1 :         buf[0] = rand();
     113            1 :         buf[1] = rand();
     114            1 :         buf[2] = rand();
     115            1 :         buf[3] = rand();
     116            1 :         CATCH_REQUIRE(v->pwrite(buf, 4, 0, false) == 4);
     117              : 
     118            1 :         CATCH_REQUIRE(v->size() == sizeof(buf));
     119            1 :         CATCH_REQUIRE(v->count_buffers() == 1);  // overwrite does not add more buffers
     120              : 
     121         1025 :         for(size_t i(0); i < sizeof(buf); ++i)
     122              :         {
     123         1024 :             char c;
     124         1024 :             CATCH_REQUIRE(v->pread(&c, sizeof(c), i, true) == sizeof(c));
     125         1024 :             CATCH_REQUIRE(buf[i] == c);
     126              :         }
     127            1 :     }
     128            6 :     CATCH_END_SECTION()
     129              : 
     130            7 :     CATCH_START_SECTION("virtual_buffer: simple write + read + erase + read")
     131              :     {
     132            1 :         prinbee::virtual_buffer::pointer_t v(std::make_shared<prinbee::virtual_buffer>());
     133            1 :         CATCH_REQUIRE(v->size() == 0);
     134            1 :         CATCH_REQUIRE(v->count_buffers() == 0);
     135              : 
     136            1 :         constexpr std::size_t const buf_size(1024 * 8);
     137            1 :         char buf[buf_size];
     138         8193 :         for(std::size_t i(0); i < sizeof(buf); ++i)
     139              :         {
     140         8192 :             buf[i] = rand();
     141              :         }
     142            1 :         CATCH_REQUIRE(v->pwrite(buf, sizeof(buf), 0, true) == sizeof(buf));
     143              : 
     144            1 :         CATCH_REQUIRE(v->size() == sizeof(buf));
     145            1 :         CATCH_REQUIRE(v->count_buffers() == 1);  // one write means at most 1 buffer
     146              : 
     147            1 :         char saved[buf_size];
     148            1 :         CATCH_REQUIRE(v->pread(saved, sizeof(saved), 0, true) == sizeof(saved));
     149              : 
     150            1 :         CATCH_REQUIRE(sizeof(buf) == sizeof(saved));
     151            1 :         CATCH_REQUIRE(memcmp(buf, saved, sizeof(buf)) == 0);
     152              : 
     153              :         // erase 1024 bytes at offset 4096
     154              :         //
     155            1 :         CATCH_REQUIRE(v->perase(1024, 4096) == 1024);
     156            1 :         CATCH_REQUIRE(v->pread(saved, 4096, 0, true) == 4096);
     157            1 :         CATCH_REQUIRE(memcmp(buf, saved, 4096) == 0);
     158            1 :         CATCH_REQUIRE(v->pread(saved, 3072, 4096, true) == 3072);
     159            1 :         CATCH_REQUIRE(memcmp(buf + 4096 + 1024, saved, 3072) == 0);
     160            1 :     }
     161            6 :     CATCH_END_SECTION()
     162              : 
     163            7 :     CATCH_START_SECTION("virtual_buffer: many writes + read + (erase + read) * N")
     164              :     {
     165            1 :         prinbee::virtual_buffer::pointer_t v(std::make_shared<prinbee::virtual_buffer>());
     166            1 :         CATCH_REQUIRE(v->size() == 0);
     167            1 :         CATCH_REQUIRE(v->count_buffers() == 0);
     168              : 
     169              :         // create a buffer of many Kb (at least 150Kb up to 512Kb
     170              :         //
     171            1 :         std::uint64_t buf_size(0);
     172              :         for(;;)
     173              :         {
     174            2 :             SNAP_CATCH2_NAMESPACE::random(buf_size);
     175            2 :             buf_size %= 512 * 1024;
     176            2 :             ++buf_size;
     177            2 :             if(buf_size >= 150 * 1024)
     178              :             {
     179            1 :                 break;
     180              :             }
     181              :         }
     182            1 :         prinbee::buffer_t buf;
     183            1 :         buf.reserve(buf_size);
     184       206571 :         for(std::uint64_t i(0); i < buf_size; ++i)
     185              :         {
     186       206570 :             buf.push_back(rand());
     187              :         }
     188              : 
     189              :         // write the buffer in small chunks so that way we get "many"
     190              :         // virtual buffers instead of one large one
     191              :         //
     192            1 :         std::uint64_t written(0);
     193          414 :         while(written < buf_size)
     194              :         {
     195          413 :             std::uint64_t sz(0);
     196          413 :             SNAP_CATCH2_NAMESPACE::random(sz);
     197          413 :             sz %= 1024;
     198          413 :             ++sz; // 1 to 1024
     199          413 :             sz = std::min(buf_size - written, sz);
     200          413 :             CATCH_REQUIRE(v->pwrite(buf.data() + written, sz, written, true) == static_cast<int>(sz));
     201          413 :             written += sz;
     202          413 :             CATCH_REQUIRE(v->size() == written);
     203              :         }
     204              : 
     205            1 :         CATCH_REQUIRE(v->size() == buf_size);
     206            1 :         CATCH_REQUIRE(v->count_buffers() > 1);
     207              : 
     208              :         // verify we can read the whole lot of data and it is equal to buffer
     209              :         //
     210            3 :         prinbee::buffer_t saved(buf_size);
     211            1 :         CATCH_REQUIRE(v->pread(saved.data(), buf_size, 0, true) == static_cast<int>(buf_size));
     212            1 :         CATCH_REQUIRE(buf == saved);
     213              : 
     214              :         // erase the whole buffer a little bit at a time and verify the
     215              :         // result each time
     216              :         //
     217          833 :         while(v->size() > 0)
     218              :         {
     219          832 :             std::uint64_t sz(0);
     220          832 :             SNAP_CATCH2_NAMESPACE::random(sz);
     221          832 :             sz %= 512;
     222          832 :             ++sz; // 1 to 512 bytes to delete
     223          832 :             sz = std::min(sz, v->size());
     224              : 
     225          832 :             std::uint64_t offset(0);
     226          832 :             if(v->size() > sz)
     227              :             {
     228          831 :                 SNAP_CATCH2_NAMESPACE::random(offset);
     229          831 :                 offset %= v->size() - sz;
     230              :             }
     231              : 
     232          832 :             if(sz + offset == v->size())
     233              :             {
     234              :                 // a larger size at the end has no effect because we adjust
     235              :                 // it to v->size() internally
     236              :                 //
     237            1 :                 std::uint64_t const extra(rand() % 4096 + 1);
     238            2 : SNAP_LOG_WARNING << "--- perase(" << sz << " + " << extra << " [" << sz + extra << "], " << offset << "); ..." << SNAP_LOG_SEND;
     239            1 :                 CATCH_REQUIRE(v->perase(sz + extra, offset) == static_cast<int>(sz));
     240              :             }
     241              :             else
     242              :             {
     243         1662 : SNAP_LOG_WARNING << "--- perase(" << sz << ", " << offset << "); ..." << SNAP_LOG_SEND;
     244          831 :                 CATCH_REQUIRE(v->perase(sz, offset) == static_cast<int>(sz));
     245              :             }
     246              : 
     247              :             // also apply the erase to our local buffer
     248              :             //
     249          832 :             buf.erase(buf.begin() + offset, buf.begin() + offset + sz);
     250              : 
     251              :             // get a copy of the full buffer and compare, it must be 100% equal
     252              :             //
     253         2496 :             prinbee::buffer_t latest(buf.size());
     254         1664 : SNAP_LOG_WARNING << "--- read result (" << buf.size() << ") ..." << SNAP_LOG_SEND;
     255          832 :             CATCH_REQUIRE(v->pread(latest.data(), buf.size(), 0, true) == static_cast<int>(buf.size()));
     256              :             //CATCH_REQUIRE(buf == latest); -- output for this one is awful
     257          832 :             CATCH_REQUIRE_LARGE_BUFFER(buf.data(), buf.size(), latest.data(), latest.size());
     258          832 :         }
     259              :         //CATCH_REQUIRE(v->perase(1024, 4096) == 1024);
     260              :         //CATCH_REQUIRE(v->pread(saved, 4096, 0, true) == 4096);
     261              :         //CATCH_REQUIRE(memcmp(buf, saved, 4096) == 0);
     262              :         //CATCH_REQUIRE(v->pread(saved, 3072, 4096, true) == 3072);
     263              :         //CATCH_REQUIRE(memcmp(buf + 4096 + 1024, saved, 3072) == 0);
     264            1 :     }
     265            6 :     CATCH_END_SECTION()
     266            5 : }
     267              : 
     268              : 
     269              : // vim: ts=4 sw=4 et
        

Generated by: LCOV version 2.0-1

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