LCOV - code coverage report
Current view: top level - tests - catch_saturated_subtract.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 100.0 % 59 59
Test Date: 2025-08-31 07:54:46 Functions: 100.0 % 1 1
Legend: Lines: hit not hit

            Line data    Source code
       1              : // Copyright (c) 2021-2025  Made to Order Software Corp.  All Rights Reserved
       2              : //
       3              : // https://snapwebsites.org/project/snapdev
       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              : /** \file
      20              :  * \brief Verify the saturated_subtract() function.
      21              :  *
      22              :  * This file implements tests to verify that the saturated_subtract() function
      23              :  * will indeed saturate the result on an underflow.
      24              :  */
      25              : 
      26              : // self
      27              : //
      28              : #include    "catch_main.h"
      29              : 
      30              : 
      31              : 
      32              : // snapdev
      33              : //
      34              : #include    <snapdev/math.h>
      35              : #include    <snapdev/ostream_int128.h>
      36              : 
      37              : 
      38              : // last include
      39              : //
      40              : #include    <snapdev/poison.h>
      41              : 
      42              : 
      43              : // __int128 is not ISO C++ yet
      44              : #pragma GCC diagnostic ignored "-Wpedantic"
      45              : 
      46              : 
      47            5 : CATCH_TEST_CASE("saturated_subtract_uint", "[math]")
      48              : {
      49            5 :     CATCH_START_SECTION("saturated_subtract_uint8: test all possible cases with 8 bits")
      50              :     {
      51          257 :         for(std::uint32_t n(0); n < 256; ++n)
      52              :         {
      53        65792 :             for(std::uint32_t m(0); m < 256; ++m)
      54              :             {
      55        65536 :                 std::int32_t expected(n - m);
      56        65536 :                 if(expected < 0)      // easy to test in this case
      57              :                 {
      58        32640 :                     expected = 0;
      59              :                 }
      60        65536 :                 std::int32_t const result(snapdev::saturated_subtract(
      61              :                               static_cast<std::uint8_t>(n)
      62        65536 :                             , static_cast<std::uint8_t>(m)));
      63        65536 :                 CATCH_REQUIRE(result == expected);
      64              :             }
      65              :         }
      66              :     }
      67            5 :     CATCH_END_SECTION()
      68              : 
      69            5 :     CATCH_START_SECTION("saturated_subtract_uint16: test many possible cases with 16 bits")
      70              :     {
      71         1333 :         for(std::uint32_t n(0); n < 65536; n += rand() % 100)
      72              :         {
      73      1764556 :             for(std::uint32_t m(0); m < 65536; m += rand() % 100)
      74              :             {
      75      1763224 :                 std::int32_t expected(n - m);
      76      1763224 :                 if(expected < 0)      // easy to test in this case
      77              :                 {
      78       878092 :                     expected = 0;
      79              :                 }
      80      1763224 :                 std::int32_t const result(snapdev::saturated_subtract(
      81              :                               static_cast<std::uint16_t>(n)
      82      1763224 :                             , static_cast<std::uint16_t>(m)));
      83      1763224 :                 CATCH_REQUIRE(result == expected);
      84              :             }
      85              :         }
      86              :     }
      87            5 :     CATCH_END_SECTION()
      88              : 
      89            5 :     CATCH_START_SECTION("saturated_subtract: test a few possible cases with 32 bits")
      90              :     {
      91              :         // no underflow at all
      92              :         {
      93            1 :             std::uint32_t const result(snapdev::saturated_subtract(
      94              :                           static_cast<std::uint32_t>(32'000)
      95              :                         , static_cast<std::uint32_t>(1'000)));
      96            1 :             CATCH_REQUIRE(result == 31'000UL);
      97              :         }
      98              : 
      99              :         // no underflow, but close
     100              :         {
     101            1 :             std::uint32_t const result(snapdev::saturated_subtract(
     102              :                           static_cast<std::uint32_t>(1'000)
     103              :                         , static_cast<std::uint32_t>(1'000)));
     104            1 :             CATCH_REQUIRE(result == std::numeric_limits<std::uint32_t>::min());
     105              :         }
     106              : 
     107              :         // underflow by 1
     108              :         {
     109            1 :             std::uint32_t const result(snapdev::saturated_subtract(
     110              :                           static_cast<std::uint32_t>(1'000)
     111              :                         , static_cast<std::uint32_t>(1'001)));
     112            1 :             CATCH_REQUIRE(result == std::numeric_limits<std::uint32_t>::min());
     113              :         }
     114              : 
     115              :         // definitive underflow
     116              :         {
     117            1 :             std::uint32_t const result(snapdev::saturated_subtract(
     118              :                           static_cast<std::uint32_t>(1'000)
     119              :                         , static_cast<std::uint32_t>(3'501)));
     120            1 :             CATCH_REQUIRE(result == std::numeric_limits<std::uint32_t>::min());
     121              :         }
     122              : 
     123              :         // max. underflow
     124              :         {
     125            1 :             std::uint32_t const result(snapdev::saturated_subtract(
     126              :                           std::numeric_limits<std::uint32_t>::min()
     127              :                         , std::numeric_limits<std::uint32_t>::max()));
     128            1 :             CATCH_REQUIRE(result == std::numeric_limits<std::uint32_t>::min());
     129              :         }
     130              :     }
     131            5 :     CATCH_END_SECTION()
     132              : 
     133            5 :     CATCH_START_SECTION("saturated_subtract_uint64: test a few possible cases with 64 bits")
     134              :     {
     135              :         // no underflow at all
     136              :         {
     137            1 :             std::uint64_t const result(snapdev::saturated_subtract(
     138              :                           static_cast<std::uint64_t>(32'000)
     139              :                         , static_cast<std::uint64_t>(1'000)));
     140            1 :             CATCH_REQUIRE(result == 31'000UL);
     141              :         }
     142              : 
     143              :         // no underflow, but close
     144              :         {
     145            1 :             std::uint64_t const result(snapdev::saturated_subtract(
     146              :                           static_cast<std::uint64_t>(1'000)
     147              :                         , static_cast<std::uint64_t>(1'000)));
     148            1 :             CATCH_REQUIRE(result == std::numeric_limits<std::uint64_t>::min());
     149              :         }
     150              : 
     151              :         // underflow by 1
     152              :         {
     153            1 :             std::uint64_t const result(snapdev::saturated_subtract(
     154              :                           static_cast<std::uint64_t>(1'000)
     155              :                         , static_cast<std::uint64_t>(1'001)));
     156            1 :             CATCH_REQUIRE(result == std::numeric_limits<std::uint64_t>::min());
     157              :         }
     158              : 
     159              :         // definitive underflow
     160              :         {
     161            1 :             std::uint64_t const result(snapdev::saturated_subtract(
     162              :                           static_cast<std::uint64_t>(1'000)
     163              :                         , static_cast<std::uint64_t>(3'501)));
     164            1 :             CATCH_REQUIRE(result == std::numeric_limits<std::uint64_t>::min());
     165              :         }
     166              : 
     167              :         // max. underflow
     168              :         {
     169            1 :             std::uint64_t const result(snapdev::saturated_subtract(
     170              :                           std::numeric_limits<std::uint64_t>::min()
     171              :                         , std::numeric_limits<std::uint64_t>::max()));
     172            1 :             CATCH_REQUIRE(result == std::numeric_limits<std::uint64_t>::min());
     173              :         }
     174              :     }
     175            5 :     CATCH_END_SECTION()
     176              : 
     177            5 :     CATCH_START_SECTION("saturated_subtract_uint128: test a few possible cases with 128 bits")
     178              :     {
     179              : #pragma GCC diagnostic push
     180              : #pragma GCC diagnostic ignored "-Wpedantic"
     181              :         // no underflow at all
     182              :         {
     183            1 :             unsigned __int128 const result(snapdev::saturated_subtract(
     184              :                           static_cast<unsigned __int128>(32'000)
     185              :                         , static_cast<unsigned __int128>(1'000)));
     186            1 :             CATCH_REQUIRE(result == 31'000UL);
     187              :         }
     188              : 
     189              :         // no underflow, but close
     190              :         {
     191            1 :             unsigned __int128 const result(snapdev::saturated_subtract(
     192              :                           static_cast<unsigned __int128>(1'000)
     193              :                         , static_cast<unsigned __int128>(1'000)));
     194            1 :             CATCH_REQUIRE(result == std::numeric_limits<unsigned __int128>::min());
     195              :         }
     196              : 
     197              :         // underflow by 1
     198              :         {
     199            1 :             unsigned __int128 const result(snapdev::saturated_subtract(
     200              :                           static_cast<unsigned __int128>(1'000)
     201              :                         , static_cast<unsigned __int128>(1'001)));
     202            1 :             CATCH_REQUIRE(result == std::numeric_limits<unsigned __int128>::min());
     203              :         }
     204              : 
     205              :         // definitive underflow
     206              :         {
     207            1 :             unsigned __int128 const result(snapdev::saturated_subtract(
     208              :                           static_cast<unsigned __int128>(3'501)
     209            1 :                         , std::numeric_limits<unsigned __int128>::max() - 1'000));
     210            1 :             CATCH_REQUIRE(result == std::numeric_limits<unsigned __int128>::min());
     211              :         }
     212              : 
     213              :         // max. underflow
     214              :         {
     215            1 :             unsigned __int128 const result(snapdev::saturated_subtract(
     216              :                           std::numeric_limits<unsigned __int128>::min()
     217              :                         , std::numeric_limits<unsigned __int128>::max()));
     218            1 :             CATCH_REQUIRE(result == std::numeric_limits<unsigned __int128>::min());
     219              :         }
     220              : #pragma GCC diagnostic pop
     221              :     }
     222            5 :     CATCH_END_SECTION()
     223            5 : }
     224              : 
     225              : 
     226              : // vim: ts=4 sw=4 et
        

Generated by: LCOV version 2.0-1

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