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
|