LCOV - code coverage report
Current view: top level - tests - catch_debian.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 584 606 96.4 %
Date: 2023-01-24 22:36:19 Functions: 12 13 92.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Copyright (c) 2023  Made to Order Software Corp.  All Rights Reserved
       2             : //
       3             : // https://snapwebsites.org/project/versiontheca
       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             : // tested file
      20             : //
      21             : #include    "versiontheca/debian.h"
      22             : 
      23             : 
      24             : // self
      25             : //
      26             : #include    "catch_main.h"
      27             : 
      28             : 
      29             : 
      30             : // versiontheca
      31             : //
      32             : #include    "versiontheca/basic.h"
      33             : #include    "versiontheca/exception.h"
      34             : #include    "versiontheca/versiontheca.h"
      35             : 
      36             : 
      37             : // C++
      38             : //
      39             : #include    <cstring>
      40             : #include    <iomanip>
      41             : #include    <stdexcept>
      42             : 
      43             : 
      44             : 
      45             : 
      46             : namespace
      47             : {
      48             : 
      49             : 
      50             : 
      51          35 : versiontheca::versiontheca::pointer_t create(char const * version, char const * verify = nullptr)
      52             : {
      53          70 :     versiontheca::debian::pointer_t t(std::make_shared<versiontheca::debian>());
      54          35 :     versiontheca::versiontheca::pointer_t v(std::make_shared<versiontheca::versiontheca>(t, version));
      55          35 :     CATCH_REQUIRE(v->get_version() == (verify == nullptr ? version : verify));
      56          70 :     return v;
      57             : }
      58             : 
      59             : 
      60             : 
      61           0 : std::string print_version(std::string const & version)
      62             : {
      63           0 :     std::stringstream result;
      64           0 :     for(char const * s(version.c_str()); *s != '\0'; ++s)
      65             :     {
      66           0 :         if(static_cast<unsigned char>(*s) < ' ')
      67             :         {
      68           0 :             result << "^" << static_cast<char>(*s + '@');
      69             :         }
      70           0 :         else if(static_cast<unsigned char>(*s) >= 0x80)
      71             :         {
      72           0 :             result << "\\x" << std::hex << static_cast<int>(static_cast<unsigned char>(*s));
      73             :         }
      74           0 :         else if(*s == 0x7F)
      75             :         {
      76           0 :             result << "<DEL>";
      77             :         }
      78           0 :         else if(*s == '^')
      79             :         {
      80           0 :             result << "^^";
      81             :         }
      82           0 :         else if(*s == '@')
      83             :         {
      84           0 :             result << "@@";
      85             :         }
      86             :         else
      87             :         {
      88           0 :             result << *s;
      89             :         }
      90             :     }
      91             : 
      92           0 :     return result.str();
      93             : }
      94             : 
      95             : 
      96       38483 : void check_version(std::string const & version, std::string const & error_msg)
      97             : {
      98             :     // validate_debian_version()
      99             :     {
     100             :         //char error_string[256];
     101             :         //strcpy(error_string, "no errors");
     102       76966 :         versiontheca::debian::pointer_t t(std::make_shared<versiontheca::debian>());
     103       76966 :         versiontheca::versiontheca v(t, version);
     104             :         //int valid(validate_debian_version(version, error_string, sizeof(error_string) / sizeof(error_string[0])));
     105             : //printf("from {%s} result = %d [%s] [%s]\n", print_version(version).c_str(), valid, error_string, error_msg);
     106       38483 :         if(error_msg.empty())
     107             :         {
     108       38401 : if(!v.is_valid())
     109           0 : std::cerr << "--- BAD: checked version [" << version << "], expected to be valid; err = [" << v.get_last_error(false) << "]\n";
     110             :             // in this case it must be valid
     111       38401 :             CATCH_REQUIRE(v.is_valid());
     112       38401 :             CATCH_REQUIRE(v.get_last_error().empty());
     113             :         }
     114             :         else
     115             :         {
     116          82 : if(v.is_valid())
     117           0 : std::cerr << "--- BAD: checked version [" << version << "], expected to be invalid; message: [" << error_msg << "]\n";
     118          82 : else if(v.get_last_error(false) != error_msg)
     119           0 : std::cerr << "--- BAD: checked version [" << version << "] invalid as expected, error message do not match, however: [" << v.get_last_error(false) << "] instead of [" << error_msg << "]\n";
     120          82 :             CATCH_REQUIRE_FALSE(v.is_valid());
     121          82 :             CATCH_REQUIRE(error_msg == v.get_last_error());
     122             :         }
     123             :     }
     124       38483 : }
     125             : 
     126             : 
     127             : //constexpr char const g_valid_digits[]    = "0123456789";
     128             : //constexpr std::size_t const g_valid_digits_length = std::size(g_valid_digits) - 1;
     129             : 
     130             : // WARNING: the alphanum is used by "invalid tests" and it includes a '.'
     131             : //          which will cause issues in valid tests (i.e. two periods one after
     132             : //          the other)
     133             : //
     134             : constexpr char const g_valid_alphanum[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz:-+.~";
     135             : constexpr std::size_t const g_valid_alphanum_length = std::size(g_valid_alphanum) - 1;
     136             : 
     137             : // all of the following support a '.' but we handle it specially to avoid
     138             : //
     139             : //     1. periods at the end
     140             : //     2. two periods in a row
     141             : //
     142             : constexpr char const g_valid_letters[]   = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+~";
     143             : constexpr std::size_t const g_valid_letters_length = std::size(g_valid_letters) - 1;
     144             : 
     145             : constexpr char const g_valid_letters_colon[]   = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+~:";
     146             : constexpr std::size_t const g_valid_letters_colon_length = std::size(g_valid_letters_colon) - 1;
     147             : 
     148             : constexpr char const g_valid_letters_dash[]   = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+~-";
     149             : constexpr std::size_t const g_valid_letters_dash_length = std::size(g_valid_letters_dash) - 1;
     150             : 
     151             : constexpr char const g_valid_all_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+~:-";
     152             : constexpr std::size_t const g_valid_all_chars_length = std::size(g_valid_all_chars) - 1;
     153             : 
     154             : 
     155       57205 : std::string generate_number()
     156             : {
     157       57205 :     versiontheca::part_integer_t value;
     158       57205 :     SNAP_CATCH2_NAMESPACE::random(value);
     159       57205 :     return std::to_string(value);
     160             : }
     161             : 
     162             : 
     163      460400 : std::string generate_word(char const * valid_chars, std::size_t length)
     164             : {
     165      460400 :     std::string v;
     166      460400 :     int const size(rand() % 10 + 1);
     167     2993329 :     for(int j(0); j < size; ++j)
     168             :     {
     169     2532929 :         v += valid_chars[rand() % length];
     170             :     }
     171      464320 :     while(!v.empty()
     172      462360 :        && v.back() == '-')
     173             :     {
     174        1960 :         v.back() = valid_chars[rand() % length];
     175             :     }
     176      460400 :     return v;
     177             : }
     178             : 
     179             : 
     180       57200 : std::string generate_version(
     181             :       std::size_t max
     182             :     , char const * valid_chars
     183             :     , std::size_t length
     184             :     , bool prepend_number = true)
     185             : {
     186       57200 :     std::string v;
     187       57200 :     std::size_t i(0);
     188       57200 :     if(prepend_number)
     189             :     {
     190       38400 :         v += generate_number();
     191       38400 :         ++i;
     192       38400 :         prepend_number = false;
     193             :     }
     194      978000 :     for(; i < max; ++i)
     195             :     {
     196      920800 :         if(!v.empty()
     197      460400 :         && rand() % 100 < 10)
     198             :         {
     199       44388 :             v += '.';
     200             :         }
     201      460400 :         if(prepend_number)
     202             :         {
     203           0 :             v += generate_number();
     204             :         }
     205             :         else
     206             :         {
     207      460400 :             v += generate_word(valid_chars, length);
     208             :         }
     209             :     }
     210       57200 :     return v;
     211             : }
     212             : 
     213             : 
     214             : }
     215             : // no name namespace
     216             : 
     217             : 
     218           5 : CATCH_TEST_CASE("debian_versions", "[valid]")
     219             : {
     220           6 :     CATCH_START_SECTION("debian_versions: verify test checker for version 1.0")
     221             :     {
     222           1 :         check_version("1.0", std::string());
     223             :     }
     224             :     CATCH_END_SECTION()
     225             : 
     226           6 :     CATCH_START_SECTION("debian_versions: verify that canonicalization happens")
     227             :     {
     228             :         {
     229           2 :             versiontheca::debian::pointer_t t(std::make_shared<versiontheca::debian>());
     230           2 :             versiontheca::versiontheca::pointer_t v(std::make_shared<versiontheca::versiontheca>(t, "3"));
     231           1 :             CATCH_REQUIRE(v->get_version() == "3.0");
     232           1 :             CATCH_REQUIRE(v->get_major() == 3);
     233           1 :             CATCH_REQUIRE(v->get_minor() == 0);
     234           1 :             CATCH_REQUIRE(v->get_patch() == 0);
     235           1 :             CATCH_REQUIRE(v->get_build() == 0);
     236             :         }
     237             :         {
     238           2 :             versiontheca::debian::pointer_t t(std::make_shared<versiontheca::debian>());
     239           2 :             versiontheca::versiontheca::pointer_t v(std::make_shared<versiontheca::versiontheca>(t, "1.0.0"));
     240           1 :             CATCH_REQUIRE(v->get_version() == "1.0");
     241             :         }
     242             :         {
     243           2 :             versiontheca::debian::pointer_t t(std::make_shared<versiontheca::debian>());
     244           2 :             versiontheca::versiontheca::pointer_t v(std::make_shared<versiontheca::versiontheca>(t, "1.0.0.0"));
     245           1 :             CATCH_REQUIRE(v->get_version() == "1.0");
     246             :         }
     247             :         {
     248           2 :             versiontheca::debian::pointer_t t(std::make_shared<versiontheca::debian>());
     249           2 :             versiontheca::versiontheca::pointer_t v(std::make_shared<versiontheca::versiontheca>(t, "0:2.71:3z"));
     250           1 :             CATCH_REQUIRE(v->get_version() == "0:2.71:3z");
     251             :         }
     252             :         {
     253           2 :             versiontheca::debian::pointer_t t(std::make_shared<versiontheca::debian>());
     254           2 :             versiontheca::versiontheca::pointer_t v(std::make_shared<versiontheca::versiontheca>(t, "0:2.71.3z-rc32.5"));
     255           1 :             CATCH_REQUIRE(v->get_version() == "2.71.3z-rc32.5");
     256             :         }
     257             :     }
     258             :     CATCH_END_SECTION()
     259             : 
     260           6 :     CATCH_START_SECTION("debian_versions: many valid versions")
     261             :     {
     262             :         // many valid versions generated randomly to increase the likelyhood
     263             :         // of things I would otherwise not think of
     264             :         //
     265       10001 :         for(int i(0); i < 10'000; ++i)
     266             :         {
     267       10000 :             int const parts(i % 25 + 1);
     268             : 
     269             :             // simple version (no epoch/revision)
     270             :             {
     271       20000 :                 std::string v(generate_version(parts, g_valid_letters, g_valid_letters_length));
     272       10000 :                 check_version(v.c_str(), std::string());
     273             :             }
     274             : 
     275             :             // epoch + version
     276       10000 :             if(parts > 1)
     277             :             {
     278       19200 :                 std::stringstream ss;
     279        9600 :                 ss << generate_number() << ':';
     280        9600 :                 ss << generate_version(parts - 1, g_valid_letters_colon, g_valid_letters_colon_length);
     281        9600 :                 check_version(ss.str(), std::string());
     282             :             }
     283             : 
     284             :             // version + revision
     285       10000 :             if(parts > 1)
     286             :             {
     287       19200 :                 std::string v(generate_version(std::max(1UL, parts / 2UL), g_valid_letters_dash, g_valid_letters_dash_length));
     288        9600 :                 v += '-';
     289        9600 :                 v += generate_version(std::max(1UL, parts / 2UL), g_valid_letters, g_valid_letters_length, false);
     290        9600 :                 check_version(v.c_str(), std::string());
     291             :             }
     292             : 
     293             :             // epoch + version + revision
     294       10000 :             if(parts > 2)
     295             :             {
     296       18400 :                 std::stringstream ss;
     297       18400 :                 ss << generate_number() << ':'
     298             :                       // anything can appear in upstream version when we have an epoch & revision
     299       18400 :                    << generate_version(std::max(1UL, parts / 2UL), g_valid_all_chars, g_valid_all_chars_length)
     300             :                    << '-'
     301             :                       // no dashes, no colons in revisions
     302       27600 :                    << generate_version(std::max(1UL, parts / 2UL), g_valid_letters, g_valid_letters_length, false);
     303        9200 :                 check_version(ss.str(), std::string());
     304             :             }
     305             :         }
     306             :     }
     307             :     CATCH_END_SECTION()
     308           3 : }
     309             : 
     310             : 
     311           7 : CATCH_TEST_CASE("next_previous_debian_versions", "[valid][next][previous]")
     312             : {
     313          10 :     CATCH_START_SECTION("next_previous_debian_versions: next/previous at level 4, 3, 2, 1, 0")
     314             :     {
     315             :         {
     316           2 :             versiontheca::versiontheca::pointer_t a(create("1.3.2"));
     317           1 :             CATCH_REQUIRE(a->next(4));
     318           1 :             CATCH_REQUIRE(a->get_version() == "1.3.2.0.1");
     319           1 :             CATCH_REQUIRE(a->previous(4));
     320           1 :             CATCH_REQUIRE(a->get_version() == "1.3.2"); // +1 -1, back to original
     321           1 :             CATCH_REQUIRE(a->previous(4));
     322           1 :             CATCH_REQUIRE(a->get_version() == "1.3.1.4294967295.4294967295");
     323           1 :             CATCH_REQUIRE(a->get_major() == 1);
     324           1 :             CATCH_REQUIRE(a->get_minor() == 3);
     325           1 :             CATCH_REQUIRE(a->get_patch() == 1);
     326           1 :             CATCH_REQUIRE(a->get_build() == 4294967295);
     327           1 :             CATCH_REQUIRE(a->next(4));
     328           1 :             CATCH_REQUIRE(a->get_version() == "1.3.2"); // +1 -1 -1 +1, back to original
     329             :         }
     330             : 
     331             :         {
     332           2 :             versiontheca::versiontheca::pointer_t a(create("1.3.2"));
     333           1 :             CATCH_REQUIRE(a->next(3));
     334           1 :             CATCH_REQUIRE(a->get_version() == "1.3.2.1");
     335           1 :             CATCH_REQUIRE(a->previous(3));
     336           1 :             CATCH_REQUIRE(a->get_version() == "1.3.2");
     337           1 :             CATCH_REQUIRE(a->previous(3));
     338           1 :             CATCH_REQUIRE(a->get_version() == "1.3.1.4294967295");
     339           1 :             CATCH_REQUIRE(a->next(3));
     340           1 :             CATCH_REQUIRE(a->get_version() == "1.3.2");
     341             :         }
     342             : 
     343             :         {
     344           2 :             versiontheca::versiontheca::pointer_t a(create("1.3.2"));
     345           1 :             CATCH_REQUIRE(a->next(2));
     346           1 :             CATCH_REQUIRE(a->get_version() == "1.3.3");
     347           1 :             CATCH_REQUIRE(a->previous(2));
     348           1 :             CATCH_REQUIRE(a->get_version() == "1.3.2");
     349           1 :             CATCH_REQUIRE(a->previous(2));
     350           1 :             CATCH_REQUIRE(a->get_version() == "1.3.1");
     351           1 :             CATCH_REQUIRE(a->next(2));
     352           1 :             CATCH_REQUIRE(a->get_version() == "1.3.2");
     353             :         }
     354             : 
     355             :         {
     356           2 :             versiontheca::versiontheca::pointer_t a(create("1.3.2"));
     357           1 :             CATCH_REQUIRE(a->next(1));
     358           1 :             CATCH_REQUIRE(a->get_version() == "1.4");
     359           1 :             CATCH_REQUIRE(a->previous(1));
     360           1 :             CATCH_REQUIRE(a->get_version() == "1.3");
     361           1 :             CATCH_REQUIRE(a->previous(1));
     362           1 :             CATCH_REQUIRE(a->get_version() == "1.2");
     363           1 :             CATCH_REQUIRE(a->next(1));
     364           1 :             CATCH_REQUIRE(a->get_version() == "1.3");
     365             :         }
     366             : 
     367             :         {
     368           2 :             versiontheca::versiontheca::pointer_t a(create("1.3.2"));
     369           1 :             CATCH_REQUIRE(a->next(0));
     370           1 :             CATCH_REQUIRE(a->get_version() == "2.0");
     371           1 :             CATCH_REQUIRE(a->previous(0));
     372           1 :             CATCH_REQUIRE(a->get_version() == "1.0");
     373           1 :             CATCH_REQUIRE(a->previous(0));
     374           1 :             CATCH_REQUIRE(a->get_version() == "0.0");
     375           1 :             CATCH_REQUIRE(a->next(0));
     376           1 :             CATCH_REQUIRE(a->get_version() == "1.0");
     377             :         }
     378             :     }
     379             :     CATCH_END_SECTION()
     380             : 
     381          10 :     CATCH_START_SECTION("next_previous_debian_versions: next/previous with letters")
     382             :     {
     383             :         {
     384           2 :             versiontheca::versiontheca::pointer_t a(create("1.3.2"));
     385           2 :             versiontheca::versiontheca::pointer_t f(create("9.9.9z.9"));
     386           1 :             CATCH_REQUIRE(a->size() == 3); // 3 on creation
     387           1 :             CATCH_REQUIRE(a->get_major() == 1);
     388           1 :             CATCH_REQUIRE(a->get_minor() == 3);
     389           1 :             CATCH_REQUIRE(a->get_patch() == 2);
     390           1 :             CATCH_REQUIRE(a->get_build() == 0);
     391           1 :             CATCH_REQUIRE(f->size() == 5); // 5 on creation (and we do not chnage that one)
     392           1 :             a->set_format(*f);
     393           1 :             CATCH_REQUIRE(a->next(4));
     394           1 :             CATCH_REQUIRE(a->size() == 5); // now it's 5
     395           1 :             CATCH_REQUIRE(a->get_major() == 1);
     396           1 :             CATCH_REQUIRE(a->get_minor() == 3);
     397           1 :             CATCH_REQUIRE(a->get_patch() == 2);
     398           1 :             CATCH_REQUIRE(a->get_build() == 0); // strings returned as 0
     399           1 :             CATCH_REQUIRE(a->get_version() == "1.3.2A.1");
     400           1 :             CATCH_REQUIRE(a->next(4));
     401           1 :             CATCH_REQUIRE(a->get_version() == "1.3.2A.2");
     402           1 :             CATCH_REQUIRE(a->next(4));
     403           1 :             CATCH_REQUIRE(a->get_version() == "1.3.2A.3");
     404           1 :             CATCH_REQUIRE(a->next(4));
     405           1 :             CATCH_REQUIRE(a->get_version() == "1.3.2A.4");
     406           1 :             CATCH_REQUIRE(a->next(4));
     407           1 :             CATCH_REQUIRE(a->get_version() == "1.3.2A.5");
     408           1 :             CATCH_REQUIRE(a->next(4));
     409           1 :             CATCH_REQUIRE(a->get_version() == "1.3.2A.6");
     410           1 :             CATCH_REQUIRE(a->next(4));
     411           1 :             CATCH_REQUIRE(a->get_version() == "1.3.2A.7");
     412           1 :             CATCH_REQUIRE(a->next(4));
     413           1 :             CATCH_REQUIRE(a->get_version() == "1.3.2A.8");
     414           1 :             CATCH_REQUIRE(a->next(4));
     415           1 :             CATCH_REQUIRE(a->get_version() == "1.3.2A.9");
     416           1 :             CATCH_REQUIRE(a->next(4));
     417           1 :             CATCH_REQUIRE(a->get_version() == "1.3.2B");
     418           1 :             CATCH_REQUIRE(a->size() == 4); // we delete zeroes
     419           1 :             CATCH_REQUIRE(a->previous(4));
     420           1 :             CATCH_REQUIRE(a->get_version() == "1.3.2A.9");
     421           1 :             CATCH_REQUIRE(a->previous(4));
     422           1 :             CATCH_REQUIRE(a->get_version() == "1.3.2A.8");
     423           1 :             CATCH_REQUIRE(a->previous(4));
     424           1 :             CATCH_REQUIRE(a->get_version() == "1.3.2A.7");
     425           1 :             CATCH_REQUIRE(a->previous(4));
     426           1 :             CATCH_REQUIRE(a->get_version() == "1.3.2A.6");
     427           1 :             CATCH_REQUIRE(a->previous(4));
     428           1 :             CATCH_REQUIRE(a->get_version() == "1.3.2A.5");
     429           1 :             CATCH_REQUIRE(a->previous(4));
     430           1 :             CATCH_REQUIRE(a->get_version() == "1.3.2A.4");
     431           1 :             CATCH_REQUIRE(a->previous(4));
     432           1 :             CATCH_REQUIRE(a->get_version() == "1.3.2A.3");
     433           1 :             CATCH_REQUIRE(a->previous(4));
     434           1 :             CATCH_REQUIRE(a->get_version() == "1.3.2A.2");
     435           1 :             CATCH_REQUIRE(a->previous(4));
     436           1 :             CATCH_REQUIRE(a->get_version() == "1.3.2A.1");
     437           1 :             CATCH_REQUIRE(a->previous(4));
     438           1 :             CATCH_REQUIRE(a->get_version() == "1.3.2");
     439           1 :             CATCH_REQUIRE(a->size() == 3); // we delete zeroes
     440           1 :             CATCH_REQUIRE(a->previous(4));
     441           1 :             CATCH_REQUIRE(a->size() == 5);
     442           1 :             CATCH_REQUIRE(a->get_version() == "1.3.1z.9");
     443           1 :             CATCH_REQUIRE(a->previous(4));
     444           1 :             CATCH_REQUIRE(a->get_version() == "1.3.1z.8");
     445           1 :             CATCH_REQUIRE(a->get_major() == 1);
     446           1 :             CATCH_REQUIRE(a->get_minor() == 3);
     447           1 :             CATCH_REQUIRE(a->get_patch() == 1);
     448           1 :             CATCH_REQUIRE(a->get_build() == 0); // strings returned as 0
     449             :         }
     450             : 
     451             :         {
     452           2 :             versiontheca::versiontheca::pointer_t a(create("1.3C"));
     453           2 :             versiontheca::versiontheca::pointer_t f(create("9.9"));
     454           1 :             CATCH_REQUIRE(a->size() == 3); // 3 on creation
     455           1 :             CATCH_REQUIRE(a->get_major() == 1);
     456           1 :             CATCH_REQUIRE(a->get_minor() == 3);
     457           1 :             CATCH_REQUIRE(a->get_patch() == 0);
     458           1 :             CATCH_REQUIRE(a->get_build() == 0);
     459           1 :             CATCH_REQUIRE(f->size() == 2);
     460           1 :             a->set_format(*f);
     461           1 :             CATCH_REQUIRE(a->previous(2));
     462           1 :             CATCH_REQUIRE(a->get_version() == "1.3B");
     463           1 :             CATCH_REQUIRE(a->previous(2));
     464           1 :             CATCH_REQUIRE(a->get_version() == "1.3");
     465           1 :             CATCH_REQUIRE(a->size() == 2);
     466           1 :             CATCH_REQUIRE(a->previous(2));
     467           1 :             CATCH_REQUIRE(a->get_version() == "1.2.4294967295");
     468             :         }
     469             : 
     470             :         {
     471           2 :             versiontheca::versiontheca::pointer_t a(create("1.3A", "1.3"));
     472           2 :             versiontheca::versiontheca::pointer_t f(create("9.9"));
     473           1 :             CATCH_REQUIRE(a->size() == 3); // 3 on creation
     474           1 :             CATCH_REQUIRE(a->get_major() == 1);
     475           1 :             CATCH_REQUIRE(a->get_minor() == 3);
     476           1 :             CATCH_REQUIRE(a->get_patch() == 0);
     477           1 :             CATCH_REQUIRE(a->get_build() == 0);
     478           1 :             CATCH_REQUIRE(f->size() == 2);
     479           1 :             a->set_format(*f);
     480           1 :             CATCH_REQUIRE(a->previous(2));
     481           1 :             CATCH_REQUIRE(a->get_version() == "1.2z");
     482           1 :             CATCH_REQUIRE(a->previous(2));
     483           1 :             CATCH_REQUIRE(a->get_version() == "1.2y");
     484             :         }
     485             :     }
     486             :     CATCH_END_SECTION()
     487             : 
     488          10 :     CATCH_START_SECTION("next_previous_debian_versions: next/previous with epoch")
     489             :     {
     490           2 :         versiontheca::versiontheca::pointer_t a(create("75:1.5.3"));
     491           1 :         CATCH_REQUIRE(a->size() == 4);
     492           1 :         CATCH_REQUIRE(a->next(2));
     493           1 :         CATCH_REQUIRE(a->get_version() == "75:1.5.4");
     494           1 :         CATCH_REQUIRE(a->previous(2));
     495           1 :         CATCH_REQUIRE(a->get_version() == "75:1.5.3");
     496           1 :         CATCH_REQUIRE(a->previous(2));
     497           1 :         CATCH_REQUIRE(a->get_version() == "75:1.5.2");
     498           1 :         CATCH_REQUIRE(a->next(2));
     499           1 :         CATCH_REQUIRE(a->get_version() == "75:1.5.3");
     500             :     }
     501             :     CATCH_END_SECTION()
     502             : 
     503          10 :     CATCH_START_SECTION("next_previous_debian_versions: next/previous with release")
     504             :     {
     505           2 :         versiontheca::versiontheca::pointer_t a(create("1.5.3-r5"));
     506           1 :         CATCH_REQUIRE(a->next(2));
     507           1 :         CATCH_REQUIRE(a->get_version() == "1.5.4-r5");
     508           1 :         CATCH_REQUIRE(a->previous(2));
     509           1 :         CATCH_REQUIRE(a->get_version() == "1.5.3-r5");
     510           1 :         CATCH_REQUIRE(a->previous(2));
     511           1 :         CATCH_REQUIRE(a->get_version() == "1.5.2-r5");
     512           1 :         CATCH_REQUIRE(a->next(2));
     513           1 :         CATCH_REQUIRE(a->get_version() == "1.5.3-r5");
     514             :     }
     515             :     CATCH_END_SECTION()
     516             : 
     517          10 :     CATCH_START_SECTION("next_previous_debian_versions: previous/next with release")
     518             :     {
     519           2 :         versiontheca::versiontheca::pointer_t a(create("5:1.5.3-r5"));
     520           1 :         CATCH_REQUIRE(a->previous(4));
     521           1 :         CATCH_REQUIRE(a->get_version() == "5:1.5.2.4294967295.4294967295-r5");
     522           1 :         CATCH_REQUIRE(a->next(4));
     523           1 :         CATCH_REQUIRE(a->get_version() == "5:1.5.3-r5");
     524           1 :         CATCH_REQUIRE(a->next(4));
     525           1 :         CATCH_REQUIRE(a->get_version() == "5:1.5.3.0.1-r5");
     526           1 :         CATCH_REQUIRE(a->previous(4));
     527           1 :         CATCH_REQUIRE(a->get_version() == "5:1.5.3-r5");
     528             :     }
     529             :     CATCH_END_SECTION()
     530           5 : }
     531             : 
     532             : 
     533           5 : CATCH_TEST_CASE("compare_debian_versions", "[valid][compare]")
     534             : {
     535           6 :     CATCH_START_SECTION("compare_debian_versions: compare many versions")
     536             :     {
     537           2 :         versiontheca::versiontheca::pointer_t a(create("1.2"));
     538           2 :         versiontheca::versiontheca::pointer_t b(create("1.1"));
     539           2 :         versiontheca::versiontheca::pointer_t c(create("1.2.0.0", "1.2"));  // the zero are ignored by the compare
     540           2 :         versiontheca::versiontheca::pointer_t d(create("1:1.1"));
     541           2 :         versiontheca::versiontheca::pointer_t e(create("1.1-rc1"));
     542           2 :         versiontheca::versiontheca::pointer_t f(create("1.1-rc2"));
     543           2 :         versiontheca::versiontheca::pointer_t g(create("1.1-alpha"));
     544           2 :         versiontheca::versiontheca::pointer_t h(create("1.1~before"));
     545           2 :         versiontheca::versiontheca::pointer_t i(create("1.1-+rc1"));
     546             : 
     547           1 :         CATCH_REQUIRE(a->is_valid());
     548           1 :         CATCH_REQUIRE(b->is_valid());
     549           1 :         CATCH_REQUIRE(c->is_valid());
     550           1 :         CATCH_REQUIRE(d->is_valid());
     551           1 :         CATCH_REQUIRE(e->is_valid());
     552           1 :         CATCH_REQUIRE(f->is_valid());
     553           1 :         CATCH_REQUIRE(g->is_valid());
     554           1 :         CATCH_REQUIRE(h->is_valid());
     555           1 :         CATCH_REQUIRE(i->is_valid());
     556             : 
     557           1 :         CATCH_REQUIRE(*a == *a);
     558           1 :         CATCH_REQUIRE_FALSE(*a != *a);
     559           1 :         CATCH_REQUIRE_FALSE(*a > *a);
     560           1 :         CATCH_REQUIRE(*a >= *a);
     561           1 :         CATCH_REQUIRE_FALSE(*a < *a);
     562           1 :         CATCH_REQUIRE(*a <= *a);
     563             : 
     564           1 :         CATCH_REQUIRE_FALSE(*a == *b);
     565           1 :         CATCH_REQUIRE(*a != *b);
     566           1 :         CATCH_REQUIRE(*a > *b);
     567           1 :         CATCH_REQUIRE(*a >= *b);
     568           1 :         CATCH_REQUIRE_FALSE(*a < *b);
     569           1 :         CATCH_REQUIRE_FALSE(*a <= *b);
     570             : 
     571           1 :         CATCH_REQUIRE_FALSE(*b == *a);
     572           1 :         CATCH_REQUIRE(*b != *a);
     573           1 :         CATCH_REQUIRE_FALSE(*b > *a);
     574           1 :         CATCH_REQUIRE_FALSE(*b >= *a);
     575           1 :         CATCH_REQUIRE(*b < *a);
     576           1 :         CATCH_REQUIRE(*b <= *a);
     577             : 
     578           1 :         CATCH_REQUIRE(*a == *c);
     579           1 :         CATCH_REQUIRE_FALSE(*a != *c);
     580           1 :         CATCH_REQUIRE_FALSE(*a > *c);
     581           1 :         CATCH_REQUIRE(*a >= *c);
     582           1 :         CATCH_REQUIRE_FALSE(*a < *c);
     583           1 :         CATCH_REQUIRE(*a <= *c);
     584             : 
     585           1 :         CATCH_REQUIRE(*c == *a);
     586           1 :         CATCH_REQUIRE_FALSE(*c != *a);
     587           1 :         CATCH_REQUIRE_FALSE(*c > *a);
     588           1 :         CATCH_REQUIRE(*c >= *a);
     589           1 :         CATCH_REQUIRE_FALSE(*c < *a);
     590           1 :         CATCH_REQUIRE(*c <= *a);
     591             : 
     592           1 :         CATCH_REQUIRE_FALSE(*a == *d);
     593           1 :         CATCH_REQUIRE(*a != *d);
     594           1 :         CATCH_REQUIRE_FALSE(*a > *d);
     595           1 :         CATCH_REQUIRE_FALSE(*a >= *d);
     596           1 :         CATCH_REQUIRE(*a < *d);
     597           1 :         CATCH_REQUIRE(*a <= *d);
     598             : 
     599           1 :         CATCH_REQUIRE_FALSE(*d == *a);
     600           1 :         CATCH_REQUIRE(*d != *a);
     601           1 :         CATCH_REQUIRE(*d > *a);
     602           1 :         CATCH_REQUIRE(*d >= *a);
     603           1 :         CATCH_REQUIRE_FALSE(*d < *a);
     604           1 :         CATCH_REQUIRE_FALSE(*d <= *a);
     605             : 
     606           1 :         CATCH_REQUIRE_FALSE(*b == *d);
     607           1 :         CATCH_REQUIRE(*b != *d);
     608           1 :         CATCH_REQUIRE_FALSE(*b > *d);
     609           1 :         CATCH_REQUIRE_FALSE(*b >= *d);
     610           1 :         CATCH_REQUIRE(*b < *d);
     611           1 :         CATCH_REQUIRE(*b <= *d);
     612             : 
     613           1 :         CATCH_REQUIRE(*e == *e);
     614           1 :         CATCH_REQUIRE_FALSE(*e != *e);
     615           1 :         CATCH_REQUIRE_FALSE(*e > *e);
     616           1 :         CATCH_REQUIRE(*e >= *e);
     617           1 :         CATCH_REQUIRE_FALSE(*e < *e);
     618           1 :         CATCH_REQUIRE(*e <= *e);
     619             : 
     620           1 :         CATCH_REQUIRE_FALSE(*b == *e);
     621           1 :         CATCH_REQUIRE(*b != *e);
     622           1 :         CATCH_REQUIRE_FALSE(*b > *e);
     623           1 :         CATCH_REQUIRE_FALSE(*b >= *e);
     624           1 :         CATCH_REQUIRE(*b < *e);
     625           1 :         CATCH_REQUIRE(*b <= *e);
     626             : 
     627           1 :         CATCH_REQUIRE_FALSE(*e == *f);
     628           1 :         CATCH_REQUIRE(*e != *f);
     629           1 :         CATCH_REQUIRE_FALSE(*e > *f);
     630           1 :         CATCH_REQUIRE_FALSE(*e >= *f);
     631           1 :         CATCH_REQUIRE(*e < *f);
     632           1 :         CATCH_REQUIRE(*e <= *f);
     633             : 
     634           1 :         CATCH_REQUIRE(*g < *e);
     635           1 :         CATCH_REQUIRE(*g < *f);
     636             : 
     637           1 :         CATCH_REQUIRE_FALSE(*b == *h);
     638           1 :         CATCH_REQUIRE(*b != *h);
     639           1 :         CATCH_REQUIRE(*b > *h);
     640           1 :         CATCH_REQUIRE(*b >= *h);
     641           1 :         CATCH_REQUIRE_FALSE(*b < *h);
     642           1 :         CATCH_REQUIRE_FALSE(*b <= *h);
     643             : 
     644           1 :         CATCH_REQUIRE_FALSE(*e == *i);
     645           1 :         CATCH_REQUIRE(*e != *i);
     646           1 :         CATCH_REQUIRE_FALSE(*e > *i);
     647           1 :         CATCH_REQUIRE_FALSE(*e >= *i);
     648           1 :         CATCH_REQUIRE(*e < *i);
     649           1 :         CATCH_REQUIRE(*e <= *i);
     650             : 
     651           1 :         CATCH_REQUIRE_FALSE(*i == *e);
     652           1 :         CATCH_REQUIRE(*i != *e);
     653           1 :         CATCH_REQUIRE(*i > *e);
     654           1 :         CATCH_REQUIRE(*i >= *e);
     655           1 :         CATCH_REQUIRE_FALSE(*i < *e);
     656           1 :         CATCH_REQUIRE_FALSE(*i <= *e);
     657             : 
     658             :         {
     659           2 :             std::stringstream ss;
     660           1 :             ss << *a;
     661           1 :             CATCH_REQUIRE(ss.str() == "1.2");
     662             :         }
     663             :         {
     664           2 :             std::stringstream ss;
     665           1 :             ss << *b;
     666           1 :             CATCH_REQUIRE(ss.str() == "1.1");
     667             :         }
     668             :         {
     669           2 :             std::stringstream ss;
     670           1 :             ss << *c;
     671           1 :             CATCH_REQUIRE(ss.str() == "1.2");
     672             :         }
     673             :         {
     674           2 :             std::stringstream ss;
     675           1 :             ss << *d;
     676           1 :             CATCH_REQUIRE(ss.str() == "1:1.1");
     677             :         }
     678             :         {
     679           2 :             std::stringstream ss;
     680           1 :             ss << *e;
     681           1 :             CATCH_REQUIRE(ss.str() == "1.1-rc1");
     682             :         }
     683             :         {
     684           2 :             std::stringstream ss;
     685           1 :             ss << *f;
     686           1 :             CATCH_REQUIRE(ss.str() == "1.1-rc2");
     687             :         }
     688             :         {
     689           2 :             std::stringstream ss;
     690           1 :             ss << *g;
     691           1 :             CATCH_REQUIRE(ss.str() == "1.1-alpha");
     692             :         }
     693             :         {
     694           2 :             std::stringstream ss;
     695           1 :             ss << *h;
     696           1 :             CATCH_REQUIRE(ss.str() == "1.1~before");
     697             :         }
     698             :         {
     699           2 :             std::stringstream ss;
     700           1 :             ss << *i;
     701           1 :             CATCH_REQUIRE(ss.str() == "1.1-+rc1");
     702             :         }
     703             :     }
     704             :     CATCH_END_SECTION()
     705             : 
     706           6 :     CATCH_START_SECTION("compare_debian_versions: compare debian vs basic versions")
     707             :     {
     708           2 :         versiontheca::debian::pointer_t d(std::make_shared<versiontheca::debian>());
     709           2 :         versiontheca::versiontheca dv(d, "1.2.5");
     710           2 :         versiontheca::basic::pointer_t b(std::make_shared<versiontheca::basic>());
     711           2 :         versiontheca::versiontheca bv(b, "1.2.4");
     712             : 
     713           1 :         CATCH_REQUIRE(dv.is_valid());
     714           1 :         CATCH_REQUIRE(bv.is_valid());
     715             : 
     716           1 :         CATCH_REQUIRE_FALSE(dv == bv);
     717           1 :         CATCH_REQUIRE(dv != bv);
     718           1 :         CATCH_REQUIRE(dv > bv);
     719           1 :         CATCH_REQUIRE(dv >= bv);
     720           1 :         CATCH_REQUIRE_FALSE(dv < bv);
     721           1 :         CATCH_REQUIRE_FALSE(dv <= bv);
     722             :     }
     723             :     CATCH_END_SECTION()
     724             : 
     725           6 :     CATCH_START_SECTION("compare_debian_versions: verify case sensitivity")
     726             :     {
     727           2 :         versiontheca::versiontheca::pointer_t a(create("53A2z"));
     728           2 :         versiontheca::versiontheca::pointer_t b(create("53a2z"));
     729             : 
     730           1 :         CATCH_REQUIRE(*a < *b);
     731             : 
     732           1 :         CATCH_REQUIRE(a->get_major() == 53);
     733           1 :         CATCH_REQUIRE(a->get_minor() == 0);
     734           1 :         CATCH_REQUIRE(a->get_patch() == 2);
     735           1 :         CATCH_REQUIRE(a->get_build() == 0);
     736             : 
     737           1 :         a = create("53.2z");
     738           1 :         b = create("53.2Z");
     739             : 
     740           1 :         CATCH_REQUIRE(*a > *b);
     741             : 
     742           1 :         CATCH_REQUIRE(a->get_major() == 53);
     743           1 :         CATCH_REQUIRE(a->get_minor() == 2);
     744           1 :         CATCH_REQUIRE(a->get_patch() == 0);
     745           1 :         CATCH_REQUIRE(a->get_build() == 0);
     746             :     }
     747             :     CATCH_END_SECTION()
     748           3 : }
     749             : 
     750             : 
     751           9 : CATCH_TEST_CASE("invalid_debian_versions", "[invalid]")
     752             : {
     753          14 :     CATCH_START_SECTION("invalid_debian_versions: empty")
     754             :     {
     755             :         // empty
     756             :         //
     757             :         // note: the empty version is "invalid" as far as versions go,
     758             :         //       but it does not generetate an error message
     759             :         //
     760             :         //       -- the check_version() cannot be used here because ""
     761             :         //          is the empty string and that means a valid version
     762             :         //
     763           2 :         versiontheca::debian::pointer_t t(std::make_shared<versiontheca::debian>());
     764           2 :         versiontheca::versiontheca v(t, "");
     765           1 :         CATCH_REQUIRE_FALSE(v.is_valid());
     766           1 :         CATCH_REQUIRE(v.get_last_error().empty());
     767             : 
     768           1 :         CATCH_REQUIRE(v.get_version().empty());
     769           1 :         CATCH_REQUIRE(v.get_last_error() == "no parts to output.");
     770             :     }
     771             :     CATCH_END_SECTION()
     772             : 
     773          14 :     CATCH_START_SECTION("invalid_debian_versions: various invalid epoch")
     774             :     {
     775             :         // epoch
     776             :         //
     777           1 :         check_version("3A3:1.2.3-pre55", "epoch must be a valid integer.");
     778           1 :         check_version("33:-55", "a version value cannot be an empty string.");
     779           1 :         check_version(":", "position of ':' and/or '-' is invalid in \":\".");
     780           1 :         check_version("a:", "epoch must be a valid integer.");
     781           1 :         check_version("-10:", "position of ':' and/or '-' is invalid in \"-10:\".");
     782           1 :         check_version("99999999999999999:", "integer too large for a valid version.");
     783           1 :         check_version("3:", "a version value cannot be an empty string.");
     784           1 :         check_version("-751", "position of ':' and/or '-' is invalid in \"-751\".");
     785             :     }
     786             :     CATCH_END_SECTION()
     787             : 
     788          14 :     CATCH_START_SECTION("invalid_debian_versions: revision")
     789             :     {
     790             :         // revision
     791           1 :         check_version("-", "position of ':' and/or '-' is invalid in \"-\".");
     792           1 :         check_version("--", "a Debian version must always start with a number \"--\".");
     793           1 :         check_version("+-", "a Debian version must always start with a number \"+-\".");
     794           1 :         check_version("#-", "found unexpected character: \\U000023 in input.");
     795           1 :         check_version("55:435123-", "a version value cannot be an empty string.");
     796           1 :         check_version("-a", "position of ':' and/or '-' is invalid in \"-a\".");
     797           1 :         check_version("-0", "position of ':' and/or '-' is invalid in \"-0\".");
     798           1 :         check_version("-+", "position of ':' and/or '-' is invalid in \"-+\".");
     799           1 :         check_version("-3$7", "position of ':' and/or '-' is invalid in \"-3$7\".");
     800           1 :         check_version("32:1.2.55-3:7", "found unexpected character: \\U00003A in input.");
     801           1 :         check_version("-3.7", "position of ':' and/or '-' is invalid in \"-3.7\".");
     802             :     }
     803             :     CATCH_END_SECTION()
     804             : 
     805          14 :     CATCH_START_SECTION("invalid_debian_versions: version")
     806             :     {
     807             :         // version
     808             :         //
     809           1 :         check_version("3.7#", "found unexpected character: \\U000023 in input.");
     810           1 :         check_version("3$7", "found unexpected character: \\U000024 in input.");
     811           1 :         check_version("3;7", "found unexpected character: \\U00003B in input.");
     812             :     }
     813             :     CATCH_END_SECTION()
     814             : 
     815          14 :     CATCH_START_SECTION("invalid_debian_versions: randomized invalid character")
     816             :     {
     817             :         // do another loop for some random unicode characters
     818             :         //
     819         128 :         for(int i(1); i < 128; ++i)
     820             :         {
     821         127 :             char c(static_cast<char>(i));
     822         127 :             if(strchr(g_valid_alphanum, c) != nullptr)
     823             :             {
     824             :                 // skip all valid characters
     825          67 :                 continue;
     826             :             }
     827             :             // TODO: the following loop is really complex
     828             :             //       I want to revamp with (1) a rand() that defines which
     829             :             //       parts to generate (0, 1, 2, or 3 -- if bit 0, add epoch,
     830             :             //       if bit 1, add a release -- always have an upstream version)
     831             :             //
     832         120 :             std::string v;
     833          60 :             std::size_t bad_at(1000);
     834          60 :             bool has_release(false);
     835         780 :             for(int j(0); j < 12; ++j)
     836             :             {
     837        1440 :                 if(v.empty()
     838         660 :                 || v[v.length() - 1] == '-'
     839        1374 :                 || v[v.length() - 1] == ':')
     840             :                 {
     841         144 :                     std::stringstream ss;
     842          72 :                     ss << rand() % 10;
     843          72 :                     v += ss.str();
     844             :                 }
     845         720 :                 if(j == 6)
     846             :                 {
     847             :                     // add the spurious character now
     848             :                     //
     849          60 :                     bad_at = v.length();
     850          60 :                     v += c;
     851             :                 }
     852             :                 char vc;
     853           0 :                 do
     854             :                 {
     855         720 :                     vc = g_valid_alphanum[rand() % g_valid_alphanum_length];
     856             :                 }
     857         720 :                 while(has_release && (vc == ':' || vc == '-'));
     858         720 :                 if(vc == '-')
     859             :                 {
     860           8 :                     has_release = true;
     861             :                 }
     862        1440 :                 if(!v.empty()
     863         720 :                 && v.back() == '.'
     864         727 :                 && (vc == ':' || vc == '-' || vc == '.'))
     865             :                 {
     866           0 :                     v += 'N'; // add a nugget between '.' and '-'/':'/'.'
     867             :                 }
     868         720 :                 if(vc == ':')
     869             :                 {
     870          11 :                     if(strchr(v.c_str(), ':') == nullptr)
     871             :                     {
     872             :                         // on first ':' ensure epoch is a number
     873             :                         //
     874           9 :                         std::string::size_type const p(v.find_first_not_of("0123456789"));
     875           9 :                         if(p != std::string::npos)
     876             :                         {
     877             :                             // not a number, create such
     878             :                             //
     879          10 :                             std::string const epoch(generate_number());
     880           5 :                             v = epoch + ":" + v;
     881           5 :                             bad_at += epoch.length() + 1;
     882           5 :                             continue;
     883             :                         }
     884             :                     }
     885             :                 }
     886         715 :                 v += vc;
     887             :             }
     888             : //std::cerr << "--- bad character is 0x" << static_cast<int>(c) << "\n";
     889         120 :             std::stringstream last_error;
     890          60 :             last_error << "found unexpected character: \\U"
     891          60 :                        << std::hex << std::uppercase << std::setfill('0')
     892          60 :                                    << std::setw(6) << static_cast<int>(c)
     893          60 :                        << " in input.";
     894             :             // check whether the bad character was inserted after the last dash
     895             :             {
     896          60 :                 std::string::size_type const p(v.find_last_of("-"));
     897          60 :                 if(p == std::string::npos)
     898             :                 {
     899          52 :                     check_version(v.c_str(), last_error.str());
     900             :                 }
     901             :                 else
     902             :                 {
     903           8 :                     if(p == v.length() - 1)
     904             :                     {
     905             :                         // avoid invalid (empty) revisions because that's not
     906             :                         // the purpose of this test
     907           4 :                         std::stringstream ss;
     908           2 :                         ss << rand() % 10;
     909           2 :                         v += ss.str();
     910             :                     }
     911           8 :                     if(p < bad_at)
     912             :                     {
     913             :                         // bad character ended up in the revision
     914           2 :                         check_version(v.c_str(), last_error.str());
     915             :                     }
     916             :                     else
     917             :                     {
     918           6 :                         if(v.find_first_of(':', p + 1) == std::string::npos)
     919             :                         {
     920           6 :                             check_version(v.c_str(), last_error.str());
     921             :                         }
     922             :                         else
     923             :                         {
     924             :                             // a revision does not accept a ':' character and since
     925             :                             // it is checked before the version we get that error
     926             :                             // instead instead of the version error...
     927           0 :                             check_version(v.c_str(), last_error.str());
     928             :                         }
     929             :                     }
     930             :                 }
     931             :             }
     932             :         }
     933             :     }
     934             :     CATCH_END_SECTION()
     935             : 
     936          14 :     CATCH_START_SECTION("invalid_debian_versions: max + 1 fails")
     937             :     {
     938           2 :         versiontheca::versiontheca::pointer_t a(create("4294967295.4294967295.4294967295"));
     939           1 :         CATCH_REQUIRE(a->is_valid());
     940           1 :         CATCH_REQUIRE_FALSE(a->next(2));
     941           1 :         CATCH_REQUIRE_FALSE(a->is_valid());
     942           1 :         CATCH_REQUIRE(a->get_last_error() == "maximum limit reached; cannot increment version any further.");
     943             :     }
     944             :     CATCH_END_SECTION()
     945             : 
     946          14 :     CATCH_START_SECTION("invalid_debian_versions: min - 1 fails")
     947             :     {
     948           2 :         versiontheca::versiontheca::pointer_t a(create("0.0"));
     949           1 :         CATCH_REQUIRE(a->is_valid());
     950           1 :         CATCH_REQUIRE_FALSE(a->previous(2));
     951           1 :         CATCH_REQUIRE_FALSE(a->is_valid());
     952           1 :         CATCH_REQUIRE(a->get_last_error() == "minimum limit reached; cannot decrement version any further.");
     953             :     }
     954             :     CATCH_END_SECTION()
     955           7 : }
     956             : 
     957             : 
     958          10 : CATCH_TEST_CASE("bad_debian_calls", "[invalid]")
     959             : {
     960          16 :     CATCH_START_SECTION("bad_debian_calls: next without a version")
     961             :     {
     962           2 :         versiontheca::debian::pointer_t t(std::make_shared<versiontheca::debian>());
     963           2 :         versiontheca::versiontheca v(t);
     964           1 :         CATCH_REQUIRE_FALSE(v.next(0));
     965           1 :         CATCH_REQUIRE(v.get_last_error() == "no parts in this Debian version; cannot compute upstream start/end.");
     966             :     }
     967             :     CATCH_END_SECTION()
     968             : 
     969          16 :     CATCH_START_SECTION("bad_debian_calls: previous without a version")
     970             :     {
     971           2 :         versiontheca::debian::pointer_t t(std::make_shared<versiontheca::debian>());
     972           2 :         versiontheca::versiontheca v(t);
     973           1 :         CATCH_REQUIRE_FALSE(v.previous(0));
     974           1 :         CATCH_REQUIRE(v.get_last_error() == "no parts in this Debian version; cannot compute upstream start/end.");
     975             :     }
     976             :     CATCH_END_SECTION()
     977             : 
     978          16 :     CATCH_START_SECTION("bad_debian_calls: next out of bounds")
     979             :     {
     980           2 :         versiontheca::versiontheca::pointer_t a(create("1.5.3-r5"));
     981         101 :         for(int p(-100); p < 0; ++p)
     982             :         {
     983         100 :             CATCH_REQUIRE_THROWS_MATCHES(
     984             :                   a->next(p)
     985             :                 , versiontheca::invalid_parameter
     986             :                 , Catch::Matchers::ExceptionMessage(
     987             :                           "versiontheca_exception: position calling next() cannot be a negative number."));
     988             :         }
     989         101 :         for(int p(versiontheca::MAX_PARTS); p < static_cast<int>(versiontheca::MAX_PARTS + 100); ++p)
     990             :         {
     991         100 :             CATCH_REQUIRE_THROWS_MATCHES(
     992             :                   a->next(p)
     993             :                 , versiontheca::invalid_parameter
     994             :                 , Catch::Matchers::ExceptionMessage(
     995             :                           "versiontheca_exception: position calling next() cannot be more than "
     996             :                         + std::to_string(versiontheca::MAX_PARTS)
     997             :                         + "."));
     998             :         }
     999             :     }
    1000             :     CATCH_END_SECTION()
    1001             : 
    1002          16 :     CATCH_START_SECTION("bad_debian_calls: previous out of bounds")
    1003             :     {
    1004           2 :         versiontheca::versiontheca::pointer_t a(create("1.5.3-r5"));
    1005         101 :         for(int p(-100); p < 0; ++p)
    1006             :         {
    1007         100 :             CATCH_REQUIRE_THROWS_MATCHES(
    1008             :                   a->previous(p)
    1009             :                 , versiontheca::invalid_parameter
    1010             :                 , Catch::Matchers::ExceptionMessage(
    1011             :                           "versiontheca_exception: position calling previous() cannot be a negative number."));
    1012             :         }
    1013         101 :         for(int p(versiontheca::MAX_PARTS); p < static_cast<int>(versiontheca::MAX_PARTS + 100); ++p)
    1014             :         {
    1015         100 :             CATCH_REQUIRE_THROWS_MATCHES(
    1016             :                   a->previous(p)
    1017             :                 , versiontheca::invalid_parameter
    1018             :                 , Catch::Matchers::ExceptionMessage(
    1019             :                           "versiontheca_exception: position calling previous() cannot be more than "
    1020             :                         + std::to_string(versiontheca::MAX_PARTS)
    1021             :                         + "."));
    1022             :         }
    1023             :     }
    1024             :     CATCH_END_SECTION()
    1025             : 
    1026          16 :     CATCH_START_SECTION("bad_debian_calls: resize out of bounds")
    1027             :     {
    1028           2 :         versiontheca::versiontheca::pointer_t a(create("1.5.3-r5"));
    1029         100 :         for(int p(versiontheca::MAX_PARTS + 1); p < static_cast<int>(versiontheca::MAX_PARTS + 100); ++p)
    1030             :         {
    1031          99 :             CATCH_REQUIRE_THROWS_MATCHES(
    1032             :                   a->get_trait()->resize(p)
    1033             :                 , versiontheca::invalid_parameter
    1034             :                 , Catch::Matchers::ExceptionMessage(
    1035             :                           "versiontheca_exception: requested too many parts."));
    1036             :         }
    1037             :     }
    1038             :     CATCH_END_SECTION()
    1039             : 
    1040          16 :     CATCH_START_SECTION("bad_debian_calls: next/erase out of bounds")
    1041             :     {
    1042           2 :         versiontheca::versiontheca::pointer_t a(create("103:1.2.3.4.5-r5with6many8release9parts"));
    1043           1 :         CATCH_REQUIRE(a->size() == 15);
    1044           1 :         CATCH_REQUIRE_THROWS_MATCHES(
    1045             :               a->next(15)  // too many because this checks total number while insert()-ing
    1046             :             , versiontheca::invalid_parameter
    1047             :             , Catch::Matchers::ExceptionMessage(
    1048             :                       "versiontheca_exception: trying to insert more parts when maximum was already reached."));
    1049           1 :         CATCH_REQUIRE(a->size() == 25);
    1050          11 :         for(int i(0); i < 10; ++i)
    1051             :         {
    1052          10 :             a->get_trait()->erase(15);
    1053             :         }
    1054           1 :         CATCH_REQUIRE(a->size() == 15);
    1055           1 :         CATCH_REQUIRE_THROWS_MATCHES(
    1056             :               a->get_trait()->erase(15)  // we have 15 left, trying to delete more will fail
    1057             :             , versiontheca::invalid_parameter
    1058             :             , Catch::Matchers::ExceptionMessage(
    1059             :                       "versiontheca_exception: trying to erase a non-existant part."));
    1060          31 :         while(a->size() > 0)
    1061             :         {
    1062          15 :             a->get_trait()->resize(a->size() - 1);
    1063             :         }
    1064             :     }
    1065             :     CATCH_END_SECTION()
    1066             : 
    1067          16 :     CATCH_START_SECTION("bad_debian_calls: compare against an empty (invalid) version")
    1068             :     {
    1069           2 :         versiontheca::versiontheca::pointer_t a(create("1.2"));
    1070           2 :         versiontheca::debian::pointer_t t(std::make_shared<versiontheca::debian>());
    1071           2 :         versiontheca::versiontheca empty(t, "");
    1072             : 
    1073           1 :         CATCH_REQUIRE(a->is_valid());
    1074           1 :         CATCH_REQUIRE_FALSE(empty.is_valid());
    1075             : 
    1076           1 :         CATCH_REQUIRE_THROWS_MATCHES(
    1077             :               a->compare(empty)
    1078             :             , versiontheca::invalid_version
    1079             :             , Catch::Matchers::ExceptionMessage(
    1080             :                       "versiontheca_exception: one or both of the input versions are not valid."));
    1081             : 
    1082           1 :         CATCH_REQUIRE_THROWS_MATCHES(
    1083             :               a->get_trait()->compare(t)
    1084             :             , versiontheca::empty_version
    1085             :             , Catch::Matchers::ExceptionMessage(
    1086             :                       "versiontheca_exception: one or both of the input versions are empty."));
    1087             :     }
    1088             :     CATCH_END_SECTION()
    1089             : 
    1090          16 :     CATCH_START_SECTION("bad_debian_calls: compare using an empty (invalid) version")
    1091             :     {
    1092           2 :         versiontheca::debian::pointer_t t(std::make_shared<versiontheca::debian>());
    1093           2 :         versiontheca::versiontheca empty(t, "");
    1094           2 :         versiontheca::versiontheca::pointer_t b(create("5.3"));
    1095             : 
    1096           1 :         CATCH_REQUIRE_FALSE(empty.is_valid());
    1097           1 :         CATCH_REQUIRE(b->is_valid());
    1098             : 
    1099           1 :         CATCH_REQUIRE(empty.get_major() == 0);
    1100           1 :         CATCH_REQUIRE(empty.get_minor() == 0);
    1101           1 :         CATCH_REQUIRE(empty.get_patch() == 0);
    1102           1 :         CATCH_REQUIRE(empty.get_build() == 0);
    1103             : 
    1104           1 :         CATCH_REQUIRE_THROWS_MATCHES(
    1105             :               empty.compare(*b)
    1106             :             , versiontheca::invalid_version
    1107             :             , Catch::Matchers::ExceptionMessage(
    1108             :                       "versiontheca_exception: one or both of the input versions are not valid."));
    1109             : 
    1110           1 :         CATCH_REQUIRE_THROWS_MATCHES(
    1111             :               t->compare(b->get_trait())
    1112             :             , versiontheca::empty_version
    1113             :             , Catch::Matchers::ExceptionMessage(
    1114             :                       "versiontheca_exception: one or both of the input versions are empty."));
    1115             :     }
    1116             :     CATCH_END_SECTION()
    1117          14 : }
    1118             : 
    1119             : 
    1120             : 
    1121             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13