LCOV - code coverage report
Current view: top level - tests - catch_saturated_add.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 100.0 % 138 138
Test Date: 2025-07-03 19:05:49 Functions: 100.0 % 2 2
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_add() functions.
      21              :  *
      22              :  * This file implements tests to verify that the saturated_add() functions
      23              :  * will indeed saturate the result on an overflow.
      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_add_uint", "[math]")
      48              : {
      49            5 :     CATCH_START_SECTION("saturated_add_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::uint32_t expected(n + m);
      56        65536 :                 if(expected > 255)      // easy to test in this case
      57              :                 {
      58        32640 :                     expected = 255;
      59              :                 }
      60        65536 :                 std::uint32_t const result(snapdev::saturated_add(
      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_add_uint16: test many possible cases with 16 bits")
      70              :     {
      71         1344 :         for(std::uint32_t n(0); n < 65536; n += rand() % 100)
      72              :         {
      73      1781178 :             for(std::uint32_t m(0); m < 65536; m += rand() % 100)
      74              :             {
      75      1779835 :                 std::uint32_t expected(n + m);
      76      1779835 :                 if(expected > 65535)      // easy to test in this case
      77              :                 {
      78       885606 :                     expected = 65535;
      79              :                 }
      80      1779835 :                 std::uint32_t const result(snapdev::saturated_add(
      81              :                               static_cast<std::uint16_t>(n)
      82      1779835 :                             , static_cast<std::uint16_t>(m)));
      83      1779835 :                 CATCH_REQUIRE(result == expected);
      84              :             }
      85              :         }
      86              :     }
      87            5 :     CATCH_END_SECTION()
      88              : 
      89            5 :     CATCH_START_SECTION("saturated_add_uint32: test a few possible cases with 32 bits")
      90              :     {
      91              :         // no overflow at all
      92              :         {
      93            1 :             std::uint32_t const result(snapdev::saturated_add(
      94              :                           static_cast<std::uint32_t>(1'000)
      95              :                         , static_cast<std::uint32_t>(32'000)));
      96            1 :             CATCH_REQUIRE(result == 33'000);
      97              :         }
      98              : 
      99              :         // no overflow, but close
     100              :         {
     101            1 :             std::uint32_t const result(snapdev::saturated_add(
     102              :                           static_cast<std::uint32_t>(1'000)
     103            1 :                         , std::numeric_limits<std::uint32_t>::max() - 1'000));
     104            1 :             CATCH_REQUIRE(result == std::numeric_limits<std::uint32_t>::max());
     105              :         }
     106              : 
     107              :         // overflow by 1
     108              :         {
     109            1 :             std::uint32_t const result(snapdev::saturated_add(
     110              :                           static_cast<std::uint32_t>(1'001)
     111            1 :                         , std::numeric_limits<std::uint32_t>::max() - 1'000));
     112            1 :             CATCH_REQUIRE(result == std::numeric_limits<std::uint32_t>::max());
     113              :         }
     114              : 
     115              :         // definitive overflow
     116              :         {
     117            1 :             std::uint32_t const result(snapdev::saturated_add(
     118              :                           static_cast<std::uint32_t>(3'501)
     119            1 :                         , std::numeric_limits<std::uint32_t>::max() - 1'000));
     120            1 :             CATCH_REQUIRE(result == std::numeric_limits<std::uint32_t>::max());
     121              :         }
     122              : 
     123              :         // max. overflow
     124              :         {
     125            1 :             std::uint32_t const result(snapdev::saturated_add(
     126              :                           std::numeric_limits<std::uint32_t>::max()
     127              :                         , std::numeric_limits<std::uint32_t>::max()));
     128            1 :             CATCH_REQUIRE(result == std::numeric_limits<std::uint32_t>::max());
     129              :         }
     130              :     }
     131            5 :     CATCH_END_SECTION()
     132              : 
     133            5 :     CATCH_START_SECTION("saturated_add_uint64: test a few possible cases with 64 bits")
     134              :     {
     135              :         // no overflow at all
     136              :         {
     137            1 :             std::uint64_t const result(snapdev::saturated_add(
     138              :                           static_cast<std::uint64_t>(1'000)
     139              :                         , static_cast<std::uint64_t>(32'000)));
     140            1 :             CATCH_REQUIRE(result == 33'000);
     141              :         }
     142              : 
     143              :         // no overflow, but close
     144              :         {
     145            1 :             std::uint64_t const result(snapdev::saturated_add(
     146              :                           static_cast<std::uint64_t>(1'000)
     147            1 :                         , std::numeric_limits<std::uint64_t>::max() - 1'000));
     148            1 :             CATCH_REQUIRE(result == std::numeric_limits<std::uint64_t>::max());
     149              :         }
     150              : 
     151              :         // overflow by 1
     152              :         {
     153            1 :             std::uint64_t const result(snapdev::saturated_add(
     154              :                           static_cast<std::uint64_t>(1'001)
     155            1 :                         , std::numeric_limits<std::uint64_t>::max() - 1'000));
     156            1 :             CATCH_REQUIRE(result == std::numeric_limits<std::uint64_t>::max());
     157              :         }
     158              : 
     159              :         // definitive overflow
     160              :         {
     161            1 :             std::uint64_t const result(snapdev::saturated_add(
     162              :                           static_cast<std::uint64_t>(3'501)
     163            1 :                         , std::numeric_limits<std::uint64_t>::max() - 1'000));
     164            1 :             CATCH_REQUIRE(result == std::numeric_limits<std::uint64_t>::max());
     165              :         }
     166              : 
     167              :         // max. overflow
     168              :         {
     169            1 :             std::uint64_t const result(snapdev::saturated_add(
     170              :                           std::numeric_limits<std::uint64_t>::max()
     171              :                         , std::numeric_limits<std::uint64_t>::max()));
     172            1 :             CATCH_REQUIRE(result == std::numeric_limits<std::uint64_t>::max());
     173              :         }
     174              :     }
     175            5 :     CATCH_END_SECTION()
     176              : 
     177            5 :     CATCH_START_SECTION("saturated_add_uint128: test a few possible cases with 128 bits")
     178              :     {
     179              : #pragma GCC diagnostic push
     180              : #pragma GCC diagnostic ignored "-Wpedantic"
     181              :         // no overflow at all
     182              :         {
     183            1 :             unsigned __int128 const result(snapdev::saturated_add(
     184              :                           static_cast<unsigned __int128>(1'000)
     185              :                         , static_cast<unsigned __int128>(32'000)));
     186            1 :             CATCH_REQUIRE(result == 33'000);
     187              :         }
     188              : 
     189              :         // no overflow, but close
     190              :         {
     191            1 :             unsigned __int128 const result(snapdev::saturated_add(
     192              :                           static_cast<unsigned __int128>(1'000)
     193            1 :                         , std::numeric_limits<unsigned __int128>::max() - 1'000));
     194            1 :             CATCH_REQUIRE(result == std::numeric_limits<unsigned __int128>::max());
     195              :         }
     196              : 
     197              :         // overflow by 1
     198              :         {
     199            1 :             unsigned __int128 const result(snapdev::saturated_add(
     200              :                           static_cast<unsigned __int128>(1'001)
     201            1 :                         , std::numeric_limits<unsigned __int128>::max() - 1'000));
     202            1 :             CATCH_REQUIRE(result == std::numeric_limits<unsigned __int128>::max());
     203              :         }
     204              : 
     205              :         // definitive overflow
     206              :         {
     207            1 :             unsigned __int128 const result(snapdev::saturated_add(
     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>::max());
     211              :         }
     212              : 
     213              :         // max. overflow
     214              :         {
     215            1 :             unsigned __int128 const result(snapdev::saturated_add(
     216              :                           std::numeric_limits<unsigned __int128>::max()
     217              :                         , std::numeric_limits<unsigned __int128>::max()));
     218            1 :             CATCH_REQUIRE(result == std::numeric_limits<unsigned __int128>::max());
     219              :         }
     220              : #pragma GCC diagnostic pop
     221              :     }
     222            5 :     CATCH_END_SECTION()
     223            5 : }
     224              : 
     225              : 
     226            5 : CATCH_TEST_CASE("saturated_add_int", "[math]")
     227              : {
     228            5 :     CATCH_START_SECTION("saturated_add_int8: test all possible cases with 8 bits")
     229              :     {
     230          257 :         for(std::int32_t n(-128); n < 128; ++n)
     231              :         {
     232        65792 :             for(std::int32_t m(-128); m < 128; ++m)
     233              :             {
     234        65536 :                 std::int32_t expected(n + m);
     235        65536 :                 if(expected < -128)
     236              :                 {
     237         8256 :                     expected = -128;
     238              :                 }
     239        57280 :                 else if(expected > 127)
     240              :                 {
     241         8128 :                     expected = 127;
     242              :                 }
     243        65536 :                 std::int32_t const result(snapdev::saturated_add(
     244              :                               static_cast<std::int8_t>(n)
     245        65536 :                             , static_cast<std::int8_t>(m)));
     246        65536 :                 CATCH_REQUIRE(result == expected);
     247              :             }
     248              :         }
     249              :     }
     250            5 :     CATCH_END_SECTION()
     251              : 
     252            5 :     CATCH_START_SECTION("saturated_add_int16: test many possible cases with 16 bits")
     253              :     {
     254         1356 :         for(std::int32_t n(-32768); n < 32768; n += rand() % 100)
     255              :         {
     256      1795929 :             for(std::int32_t m(-32768); m < 32768; m += rand() % 100)
     257              :             {
     258      1794574 :                 std::int32_t expected(n + m);
     259      1794574 :                 if(expected < -32768)
     260              :                 {
     261       227156 :                     expected = -32768;
     262              :                 }
     263      1567418 :                 else if(expected > 32767)
     264              :                 {
     265       227259 :                     expected = 32767;
     266              :                 }
     267      1794574 :                 std::int32_t const result(snapdev::saturated_add(
     268              :                               static_cast<std::int16_t>(n)
     269      1794574 :                             , static_cast<std::int16_t>(m)));
     270      1794574 :                 CATCH_REQUIRE(result == expected);
     271              :             }
     272              :         }
     273              :     }
     274            5 :     CATCH_END_SECTION()
     275              : 
     276            5 :     CATCH_START_SECTION("saturated_add_int32: test a few possible cases with 32 bits")
     277              :     {
     278              :         // no overflow at all
     279              :         {
     280            1 :             std::int32_t const result(snapdev::saturated_add(
     281              :                           static_cast<std::int32_t>(1'000)
     282              :                         , static_cast<std::int32_t>(33'000)));
     283            1 :             CATCH_REQUIRE(result == 34'000);
     284              :         }
     285              : 
     286              :         // no overflow, but close
     287              :         {
     288            1 :             std::int32_t const result(snapdev::saturated_add(
     289              :                           static_cast<std::int32_t>(1'000)
     290            1 :                         , std::numeric_limits<std::int32_t>::max() - 1'000));
     291            1 :             CATCH_REQUIRE(result == std::numeric_limits<std::int32_t>::max());
     292              :         }
     293              : 
     294              :         // overflow by 1
     295              :         {
     296            1 :             std::int32_t const result(snapdev::saturated_add(
     297              :                           static_cast<std::int32_t>(1'001)
     298            1 :                         , std::numeric_limits<std::int32_t>::max() - 1'000));
     299            1 :             CATCH_REQUIRE(result == std::numeric_limits<std::int32_t>::max());
     300              :         }
     301              : 
     302              :         // definitive overflow
     303              :         {
     304            1 :             std::int32_t const result(snapdev::saturated_add(
     305              :                           static_cast<std::int32_t>(3'501)
     306            1 :                         , std::numeric_limits<std::int32_t>::max() - 1'000));
     307            1 :             CATCH_REQUIRE(result == std::numeric_limits<std::int32_t>::max());
     308              :         }
     309              : 
     310              :         // max. overflow
     311              :         {
     312            1 :             std::int32_t const result(snapdev::saturated_add(
     313              :                           std::numeric_limits<std::int32_t>::max()
     314              :                         , std::numeric_limits<std::int32_t>::max()));
     315            1 :             CATCH_REQUIRE(result == std::numeric_limits<std::int32_t>::max());
     316              :         }
     317              :     }
     318            5 :     CATCH_END_SECTION()
     319              : 
     320            5 :     CATCH_START_SECTION("saturated_add_int64: test a few possible cases with 64 bits")
     321              :     {
     322              :         // no overflow at all
     323              :         {
     324            1 :             std::int64_t const result(snapdev::saturated_add(
     325              :                           static_cast<std::int64_t>(1'000)
     326              :                         , static_cast<std::int64_t>(32'000)));
     327            1 :             CATCH_REQUIRE(result == 33'000);
     328              :         }
     329              : 
     330              :         // no overflow, but close
     331              :         {
     332            1 :             std::int64_t const result(snapdev::saturated_add(
     333              :                           static_cast<std::int64_t>(1'000)
     334            1 :                         , std::numeric_limits<std::int64_t>::max() - 1'000));
     335            1 :             CATCH_REQUIRE(result == std::numeric_limits<std::int64_t>::max());
     336              :         }
     337              : 
     338              :         // overflow by 1
     339              :         {
     340            1 :             std::int64_t const result(snapdev::saturated_add(
     341              :                           static_cast<std::int64_t>(1'001)
     342            1 :                         , std::numeric_limits<std::int64_t>::max() - 1'000));
     343            1 :             CATCH_REQUIRE(result == std::numeric_limits<std::int64_t>::max());
     344              :         }
     345              : 
     346              :         // definitive overflow
     347              :         {
     348            1 :             std::int64_t const result(snapdev::saturated_add(
     349              :                           static_cast<std::int64_t>(3'501)
     350            1 :                         , std::numeric_limits<std::int64_t>::max() - 1'000));
     351            1 :             CATCH_REQUIRE(result == std::numeric_limits<std::int64_t>::max());
     352              :         }
     353              : 
     354              :         // max. overflow
     355              :         {
     356            1 :             std::int64_t const result(snapdev::saturated_add(
     357              :                           std::numeric_limits<std::int64_t>::max()
     358              :                         , std::numeric_limits<std::int64_t>::max()));
     359            1 :             CATCH_REQUIRE(result == std::numeric_limits<std::int64_t>::max());
     360              :         }
     361              :     }
     362            5 :     CATCH_END_SECTION()
     363              : 
     364            5 :     CATCH_START_SECTION("saturated_add_int128: test a few possible cases with 128 bits")
     365              :     {
     366              : #pragma GCC diagnostic push
     367              : #pragma GCC diagnostic ignored "-Wpedantic"
     368              :         // no overflow at all
     369              :         {
     370            1 :             __int128 const result(snapdev::saturated_add(
     371              :                           static_cast<__int128>(1'000LL)
     372              :                         , static_cast<__int128>(32'000'000LL)));
     373            1 :             CATCH_REQUIRE(result == 32'001'000LL);
     374              :         }
     375              : 
     376              :         // no overflow, but close
     377              :         {
     378            1 :             __int128 const result(snapdev::saturated_add(
     379              :                           static_cast<__int128>(1'000)
     380            1 :                         , std::numeric_limits<__int128>::max() - 1'000));
     381            1 :             CATCH_REQUIRE(result == std::numeric_limits<__int128>::max());
     382              :         }
     383              : 
     384              :         // overflow by 1
     385              :         {
     386            1 :             __int128 const result(snapdev::saturated_add(
     387              :                           static_cast<__int128>(1'001)
     388            1 :                         , std::numeric_limits<__int128>::max() - 1'000));
     389            1 :             CATCH_REQUIRE(result == std::numeric_limits<__int128>::max());
     390              :         }
     391              : 
     392              :         // definitive overflow
     393              :         {
     394            1 :             __int128 const result(snapdev::saturated_add(
     395              :                           static_cast<__int128>(3'501)
     396            1 :                         , std::numeric_limits<__int128>::max() - 1'000));
     397            1 :             CATCH_REQUIRE(result == std::numeric_limits<__int128>::max());
     398              :         }
     399              : 
     400              :         // max. overflow
     401              :         {
     402            1 :             __int128 const result(snapdev::saturated_add(
     403              :                           std::numeric_limits<__int128>::max()
     404              :                         , std::numeric_limits<__int128>::max()));
     405            1 :             CATCH_REQUIRE(result == std::numeric_limits<__int128>::max());
     406              :         }
     407              : #pragma GCC diagnostic pop
     408              :     }
     409            5 :     CATCH_END_SECTION()
     410            5 : }
     411              : 
     412              : 
     413              : // vim: ts=4 sw=4 et
        

Generated by: LCOV version 2.0-1

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