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/rpm.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 39 : versiontheca::versiontheca::pointer_t create(char const * version, char const * verify = nullptr)
52 : {
53 78 : versiontheca::rpm::pointer_t t(std::make_shared<versiontheca::rpm>());
54 39 : versiontheca::versiontheca::pointer_t v(std::make_shared<versiontheca::versiontheca>(t, version));
55 39 : CATCH_REQUIRE(v->get_version() == (verify == nullptr ? version : verify));
56 78 : 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 38481 : void check_version(std::string const & version, std::string const & error_msg)
97 : {
98 : // validate_rpm_version()
99 : {
100 : //char error_string[256];
101 : //strcpy(error_string, "no errors");
102 76962 : versiontheca::rpm::pointer_t t(std::make_shared<versiontheca::rpm>());
103 76962 : versiontheca::versiontheca v(t, version);
104 : //int valid(validate_rpm_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 38481 : 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 80 : if(v.is_valid())
117 0 : std::cerr << "--- BAD: checked version [" << version << "], expected to be invalid; message: [" << error_msg << "]\n";
118 80 : 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 80 : CATCH_REQUIRE_FALSE(v.is_valid());
121 80 : CATCH_REQUIRE(error_msg == v.get_last_error());
122 : }
123 : }
124 38481 : }
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 57200 : std::string generate_number()
156 : {
157 57200 : versiontheca::part_integer_t value;
158 57200 : SNAP_CATCH2_NAMESPACE::random(value);
159 57200 : 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 2992593 : for(int j(0); j < size; ++j)
168 : {
169 2532193 : v += valid_chars[rand() % length];
170 : }
171 460400 : while(!v.empty()
172 460400 : && v.back() == '-')
173 : {
174 0 : 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 44119 : 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("rpm_versions", "[valid]")
219 : {
220 6 : CATCH_START_SECTION("rpm_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("rpm_versions: verify that canonicalization happens")
227 : {
228 : {
229 2 : versiontheca::rpm::pointer_t t(std::make_shared<versiontheca::rpm>());
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::rpm::pointer_t t(std::make_shared<versiontheca::rpm>());
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::rpm::pointer_t t(std::make_shared<versiontheca::rpm>());
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::rpm::pointer_t t(std::make_shared<versiontheca::rpm>());
249 2 : versiontheca::versiontheca::pointer_t v(std::make_shared<versiontheca::versiontheca>(t, "0:q2.71-z3"));
250 1 : CATCH_REQUIRE(v->get_version() == "q2.71-z3");
251 : }
252 : {
253 2 : versiontheca::rpm::pointer_t t(std::make_shared<versiontheca::rpm>());
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("rpm_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, g_valid_letters_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, g_valid_letters_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_letters, g_valid_letters_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_rpm_versions", "[valid][next][previous]")
312 : {
313 10 : CATCH_START_SECTION("next_previous_rpm_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_rpm_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_rpm_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_rpm_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_rpm_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_rpm_versions", "[valid][compare]")
534 : {
535 6 : CATCH_START_SECTION("compare_rpm_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 2 : versiontheca::versiontheca::pointer_t j(create("1.1-rc1_"));
547 2 : versiontheca::versiontheca::pointer_t k(create("1.1q"));
548 2 : versiontheca::versiontheca::pointer_t l(create("1.1f"));
549 2 : versiontheca::versiontheca::pointer_t m(create("1.1.5"));
550 :
551 1 : CATCH_REQUIRE(a->is_valid());
552 1 : CATCH_REQUIRE(b->is_valid());
553 1 : CATCH_REQUIRE(c->is_valid());
554 1 : CATCH_REQUIRE(d->is_valid());
555 1 : CATCH_REQUIRE(e->is_valid());
556 1 : CATCH_REQUIRE(f->is_valid());
557 1 : CATCH_REQUIRE(g->is_valid());
558 1 : CATCH_REQUIRE(h->is_valid());
559 1 : CATCH_REQUIRE(i->is_valid());
560 1 : CATCH_REQUIRE(j->is_valid());
561 1 : CATCH_REQUIRE(k->is_valid());
562 1 : CATCH_REQUIRE(l->is_valid());
563 1 : CATCH_REQUIRE(m->is_valid());
564 :
565 1 : CATCH_REQUIRE(*a == *a);
566 1 : CATCH_REQUIRE_FALSE(*a != *a);
567 1 : CATCH_REQUIRE_FALSE(*a > *a);
568 1 : CATCH_REQUIRE(*a >= *a);
569 1 : CATCH_REQUIRE_FALSE(*a < *a);
570 1 : CATCH_REQUIRE(*a <= *a);
571 :
572 1 : CATCH_REQUIRE_FALSE(*a == *b);
573 1 : CATCH_REQUIRE(*a != *b);
574 1 : CATCH_REQUIRE(*a > *b);
575 1 : CATCH_REQUIRE(*a >= *b);
576 1 : CATCH_REQUIRE_FALSE(*a < *b);
577 1 : CATCH_REQUIRE_FALSE(*a <= *b);
578 :
579 1 : CATCH_REQUIRE_FALSE(*b == *a);
580 1 : CATCH_REQUIRE(*b != *a);
581 1 : CATCH_REQUIRE_FALSE(*b > *a);
582 1 : CATCH_REQUIRE_FALSE(*b >= *a);
583 1 : CATCH_REQUIRE(*b < *a);
584 1 : CATCH_REQUIRE(*b <= *a);
585 :
586 1 : CATCH_REQUIRE(*a == *c);
587 1 : CATCH_REQUIRE_FALSE(*a != *c);
588 1 : CATCH_REQUIRE_FALSE(*a > *c);
589 1 : CATCH_REQUIRE(*a >= *c);
590 1 : CATCH_REQUIRE_FALSE(*a < *c);
591 1 : CATCH_REQUIRE(*a <= *c);
592 :
593 1 : CATCH_REQUIRE(*c == *a);
594 1 : CATCH_REQUIRE_FALSE(*c != *a);
595 1 : CATCH_REQUIRE_FALSE(*c > *a);
596 1 : CATCH_REQUIRE(*c >= *a);
597 1 : CATCH_REQUIRE_FALSE(*c < *a);
598 1 : CATCH_REQUIRE(*c <= *a);
599 :
600 1 : CATCH_REQUIRE_FALSE(*a == *d);
601 1 : CATCH_REQUIRE(*a != *d);
602 1 : CATCH_REQUIRE_FALSE(*a > *d);
603 1 : CATCH_REQUIRE_FALSE(*a >= *d);
604 1 : CATCH_REQUIRE(*a < *d);
605 1 : CATCH_REQUIRE(*a <= *d);
606 :
607 1 : CATCH_REQUIRE_FALSE(*d == *a);
608 1 : CATCH_REQUIRE(*d != *a);
609 1 : CATCH_REQUIRE(*d > *a);
610 1 : CATCH_REQUIRE(*d >= *a);
611 1 : CATCH_REQUIRE_FALSE(*d < *a);
612 1 : CATCH_REQUIRE_FALSE(*d <= *a);
613 :
614 1 : CATCH_REQUIRE_FALSE(*b == *d);
615 1 : CATCH_REQUIRE(*b != *d);
616 1 : CATCH_REQUIRE_FALSE(*b > *d);
617 1 : CATCH_REQUIRE_FALSE(*b >= *d);
618 1 : CATCH_REQUIRE(*b < *d);
619 1 : CATCH_REQUIRE(*b <= *d);
620 :
621 1 : CATCH_REQUIRE(*e == *e);
622 1 : CATCH_REQUIRE_FALSE(*e != *e);
623 1 : CATCH_REQUIRE_FALSE(*e > *e);
624 1 : CATCH_REQUIRE(*e >= *e);
625 1 : CATCH_REQUIRE_FALSE(*e < *e);
626 1 : CATCH_REQUIRE(*e <= *e);
627 :
628 1 : CATCH_REQUIRE_FALSE(*b == *e);
629 1 : CATCH_REQUIRE(*b != *e);
630 1 : CATCH_REQUIRE_FALSE(*b > *e);
631 1 : CATCH_REQUIRE_FALSE(*b >= *e);
632 1 : CATCH_REQUIRE(*b < *e);
633 1 : CATCH_REQUIRE(*b <= *e);
634 :
635 1 : CATCH_REQUIRE_FALSE(*e == *f);
636 1 : CATCH_REQUIRE(*e != *f);
637 1 : CATCH_REQUIRE_FALSE(*e > *f);
638 1 : CATCH_REQUIRE_FALSE(*e >= *f);
639 1 : CATCH_REQUIRE(*e < *f);
640 1 : CATCH_REQUIRE(*e <= *f);
641 :
642 1 : CATCH_REQUIRE(*g < *e);
643 1 : CATCH_REQUIRE(*g < *f);
644 :
645 1 : CATCH_REQUIRE_FALSE(*b == *h);
646 1 : CATCH_REQUIRE(*b != *h);
647 1 : CATCH_REQUIRE(*b > *h);
648 1 : CATCH_REQUIRE(*b >= *h);
649 1 : CATCH_REQUIRE_FALSE(*b < *h);
650 1 : CATCH_REQUIRE_FALSE(*b <= *h);
651 :
652 1 : CATCH_REQUIRE(*e == *i);
653 1 : CATCH_REQUIRE_FALSE(*e != *i);
654 1 : CATCH_REQUIRE_FALSE(*e > *i);
655 1 : CATCH_REQUIRE(*e >= *i);
656 1 : CATCH_REQUIRE_FALSE(*e < *i);
657 1 : CATCH_REQUIRE(*e <= *i);
658 :
659 1 : CATCH_REQUIRE(*i == *e);
660 1 : CATCH_REQUIRE_FALSE(*i != *e);
661 1 : CATCH_REQUIRE_FALSE(*i > *e);
662 1 : CATCH_REQUIRE(*i >= *e);
663 1 : CATCH_REQUIRE_FALSE(*i < *e);
664 1 : CATCH_REQUIRE(*i <= *e);
665 :
666 1 : CATCH_REQUIRE(*e == *j);
667 1 : CATCH_REQUIRE_FALSE(*e != *j);
668 1 : CATCH_REQUIRE_FALSE(*e > *j);
669 1 : CATCH_REQUIRE(*e >= *j);
670 1 : CATCH_REQUIRE_FALSE(*e < *j);
671 1 : CATCH_REQUIRE(*e <= *j);
672 :
673 1 : CATCH_REQUIRE(*j == *e);
674 1 : CATCH_REQUIRE_FALSE(*j != *e);
675 1 : CATCH_REQUIRE_FALSE(*j > *e);
676 1 : CATCH_REQUIRE(*j >= *e);
677 1 : CATCH_REQUIRE_FALSE(*j < *e);
678 1 : CATCH_REQUIRE(*j <= *e);
679 :
680 1 : CATCH_REQUIRE(*i == *j);
681 1 : CATCH_REQUIRE_FALSE(*i != *j);
682 1 : CATCH_REQUIRE_FALSE(*i > *j);
683 1 : CATCH_REQUIRE(*i >= *j);
684 1 : CATCH_REQUIRE_FALSE(*i < *j);
685 1 : CATCH_REQUIRE(*i <= *j);
686 :
687 1 : CATCH_REQUIRE(*j == *i);
688 1 : CATCH_REQUIRE_FALSE(*j != *i);
689 1 : CATCH_REQUIRE_FALSE(*j > *i);
690 1 : CATCH_REQUIRE(*j >= *i);
691 1 : CATCH_REQUIRE_FALSE(*j < *i);
692 1 : CATCH_REQUIRE(*j <= *i);
693 :
694 1 : CATCH_REQUIRE(*k > *l);
695 1 : CATCH_REQUIRE(*l < *k);
696 1 : CATCH_REQUIRE(*c > *k);
697 1 : CATCH_REQUIRE(*c > *l);
698 1 : CATCH_REQUIRE(*k < *c);
699 1 : CATCH_REQUIRE(*l < *c);
700 1 : CATCH_REQUIRE(*m > *k);
701 1 : CATCH_REQUIRE(*m > *l);
702 1 : CATCH_REQUIRE(*k < *m);
703 1 : CATCH_REQUIRE(*l < *m);
704 :
705 : {
706 2 : std::stringstream ss;
707 1 : ss << *a;
708 1 : CATCH_REQUIRE(ss.str() == "1.2");
709 : }
710 : {
711 2 : std::stringstream ss;
712 1 : ss << *b;
713 1 : CATCH_REQUIRE(ss.str() == "1.1");
714 : }
715 : {
716 2 : std::stringstream ss;
717 1 : ss << *c;
718 1 : CATCH_REQUIRE(ss.str() == "1.2");
719 : }
720 : {
721 2 : std::stringstream ss;
722 1 : ss << *d;
723 1 : CATCH_REQUIRE(ss.str() == "1:1.1");
724 : }
725 : {
726 2 : std::stringstream ss;
727 1 : ss << *e;
728 1 : CATCH_REQUIRE(ss.str() == "1.1-rc1");
729 : }
730 : {
731 2 : std::stringstream ss;
732 1 : ss << *f;
733 1 : CATCH_REQUIRE(ss.str() == "1.1-rc2");
734 : }
735 : {
736 2 : std::stringstream ss;
737 1 : ss << *g;
738 1 : CATCH_REQUIRE(ss.str() == "1.1-alpha");
739 : }
740 : {
741 2 : std::stringstream ss;
742 1 : ss << *h;
743 1 : CATCH_REQUIRE(ss.str() == "1.1~before");
744 : }
745 : {
746 2 : std::stringstream ss;
747 1 : ss << *i;
748 1 : CATCH_REQUIRE(ss.str() == "1.1-_rc1");
749 : }
750 : }
751 : CATCH_END_SECTION()
752 :
753 6 : CATCH_START_SECTION("compare_rpm_versions: compare rpm vs basic versions")
754 : {
755 2 : versiontheca::rpm::pointer_t d(std::make_shared<versiontheca::rpm>());
756 2 : versiontheca::versiontheca dv(d, "1.2.5");
757 2 : versiontheca::basic::pointer_t b(std::make_shared<versiontheca::basic>());
758 2 : versiontheca::versiontheca bv(b, "1.2.4");
759 :
760 1 : CATCH_REQUIRE(dv.is_valid());
761 1 : CATCH_REQUIRE(bv.is_valid());
762 :
763 1 : CATCH_REQUIRE_FALSE(dv == bv);
764 1 : CATCH_REQUIRE(dv != bv);
765 1 : CATCH_REQUIRE(dv > bv);
766 1 : CATCH_REQUIRE(dv >= bv);
767 1 : CATCH_REQUIRE_FALSE(dv < bv);
768 1 : CATCH_REQUIRE_FALSE(dv <= bv);
769 : }
770 : CATCH_END_SECTION()
771 :
772 6 : CATCH_START_SECTION("compare_rpm_versions: verify case sensitivity")
773 : {
774 2 : versiontheca::versiontheca::pointer_t a(create("53A2z"));
775 2 : versiontheca::versiontheca::pointer_t b(create("53a2z"));
776 :
777 1 : CATCH_REQUIRE(*a < *b);
778 :
779 1 : CATCH_REQUIRE(a->get_major() == 53);
780 1 : CATCH_REQUIRE(a->get_minor() == 0);
781 1 : CATCH_REQUIRE(a->get_patch() == 2);
782 1 : CATCH_REQUIRE(a->get_build() == 0);
783 :
784 1 : a = create("53.2z");
785 1 : b = create("53.2Z");
786 :
787 1 : CATCH_REQUIRE(*a > *b);
788 :
789 1 : CATCH_REQUIRE(a->get_major() == 53);
790 1 : CATCH_REQUIRE(a->get_minor() == 2);
791 1 : CATCH_REQUIRE(a->get_patch() == 0);
792 1 : CATCH_REQUIRE(a->get_build() == 0);
793 : }
794 : CATCH_END_SECTION()
795 3 : }
796 :
797 :
798 9 : CATCH_TEST_CASE("invalid_rpm_versions", "[invalid]")
799 : {
800 14 : CATCH_START_SECTION("invalid_rpm_versions: empty")
801 : {
802 : // empty
803 : //
804 : // note: the empty version is "invalid" as far as versions go,
805 : // but it does not generetate an error message
806 : //
807 : // -- the check_version() cannot be used here because ""
808 : // is the empty string and that means a valid version
809 : //
810 2 : versiontheca::rpm::pointer_t t(std::make_shared<versiontheca::rpm>());
811 2 : versiontheca::versiontheca v(t, "");
812 1 : CATCH_REQUIRE_FALSE(v.is_valid());
813 1 : CATCH_REQUIRE(v.get_last_error().empty());
814 :
815 1 : CATCH_REQUIRE(v.get_version().empty());
816 1 : CATCH_REQUIRE(v.get_last_error() == "no parts to output.");
817 : }
818 : CATCH_END_SECTION()
819 :
820 14 : CATCH_START_SECTION("invalid_rpm_versions: various invalid epoch")
821 : {
822 : // epoch
823 : //
824 1 : check_version("3A3:1.2.3-pre55", "epoch must be a valid integer.");
825 1 : check_version("33:-55", "a version value cannot be an empty string.");
826 1 : check_version(":", "position of ':' and/or '-' is invalid in \":\".");
827 1 : check_version("a:", "epoch must be a valid integer.");
828 1 : check_version("-10:", "position of ':' and/or '-' is invalid in \"-10:\".");
829 1 : check_version("99999999999999999:", "integer too large for a valid version.");
830 1 : check_version("3:", "a version value cannot be an empty string.");
831 1 : check_version("-751", "position of ':' and/or '-' is invalid in \"-751\".");
832 : }
833 : CATCH_END_SECTION()
834 :
835 14 : CATCH_START_SECTION("invalid_rpm_versions: revision")
836 : {
837 : // revision
838 1 : check_version("-", "position of ':' and/or '-' is invalid in \"-\".");
839 1 : check_version("--", "found unexpected character: \\U00002D in input.");
840 1 : check_version("+-", "a version value cannot be an empty string.");
841 1 : check_version("#-", "found unexpected character: \\U000023 in input.");
842 1 : check_version("55:435123-", "a version value cannot be an empty string.");
843 1 : check_version("-a", "position of ':' and/or '-' is invalid in \"-a\".");
844 1 : check_version("-0", "position of ':' and/or '-' is invalid in \"-0\".");
845 1 : check_version("-+", "position of ':' and/or '-' is invalid in \"-+\".");
846 1 : check_version("-3$7", "position of ':' and/or '-' is invalid in \"-3$7\".");
847 1 : check_version("32:1.2.55-3:7", "found unexpected character: \\U00003A in input.");
848 1 : check_version("-3.7", "position of ':' and/or '-' is invalid in \"-3.7\".");
849 : }
850 : CATCH_END_SECTION()
851 :
852 14 : CATCH_START_SECTION("invalid_rpm_versions: version")
853 : {
854 : // version
855 : //
856 1 : check_version("3.7#", "found unexpected character: \\U000023 in input.");
857 1 : check_version("3$7", "found unexpected character: \\U000024 in input.");
858 1 : check_version("3;7", "found unexpected character: \\U00003B in input.");
859 : }
860 : CATCH_END_SECTION()
861 :
862 14 : CATCH_START_SECTION("invalid_rpm_versions: randomized invalid characters")
863 : {
864 : // do another loop for some random unicode characters
865 : //
866 128 : for(int i(1); i < 128; ++i)
867 : {
868 127 : char c(static_cast<char>(i));
869 127 : if(strchr(g_valid_alphanum, c) != nullptr || c == '+')
870 : {
871 : // skip all valid characters
872 : //
873 69 : continue;
874 : }
875 : // TODO: the following loop is really complex
876 : // I want to revamp with (1) a rand() that defines which
877 : // parts to generate (0, 1, 2, or 3 -- if bit 0, add epoch,
878 : // if bit 1, add a release -- always have an upstream version)
879 : //
880 116 : std::string v;
881 58 : std::size_t bad_at(1000);
882 58 : bool has_release(false);
883 58 : if(rand() % 10 == 0)
884 : {
885 20 : std::stringstream ss;
886 10 : ss << rand() << ':';
887 10 : v += ss.str();
888 : }
889 754 : for(int j(0); j < 12; ++j)
890 : {
891 696 : if(j == 6)
892 : {
893 : // add the spurious character now
894 : //
895 58 : bad_at = v.length();
896 58 : v += c;
897 : }
898 : char vc;
899 33 : do
900 : {
901 729 : vc = g_valid_alphanum[rand() % g_valid_alphanum_length];
902 : }
903 676 : while(((has_release || v.empty() || v.back() == ':') && vc == '-')
904 728 : || (v.empty() && vc == '.')
905 727 : || vc == ':'
906 719 : || vc == '^'
907 1436 : || vc == '~');
908 696 : if(vc == '-')
909 : {
910 11 : has_release = true;
911 : }
912 1392 : if(!v.empty()
913 648 : && v.back() == '.'
914 707 : && (vc == '-' || vc == '.'))
915 : {
916 0 : v += 'N'; // add a nugget between '.' and '-'/'.'
917 : }
918 696 : v += vc;
919 : }
920 : //std::cerr << "--- bad character is 0x" << static_cast<int>(c) << "\n";
921 116 : std::stringstream last_error;
922 58 : last_error << "found unexpected character: \\U"
923 58 : << std::hex << std::uppercase << std::setfill('0')
924 58 : << std::setw(6) << static_cast<int>(c)
925 58 : << " in input.";
926 : // check whether the bad character was inserted after the last dash
927 : {
928 58 : std::string::size_type const p(v.find_last_of("-"));
929 58 : if(p == std::string::npos)
930 : {
931 47 : check_version(v.c_str(), last_error.str());
932 : }
933 : else
934 : {
935 11 : if(p == v.length() - 1)
936 : {
937 : // avoid invalid (empty) revisions because that's not
938 : // the purpose of this test
939 2 : std::stringstream ss;
940 1 : ss << rand() % 10;
941 1 : v += ss.str();
942 : }
943 11 : if(p < bad_at)
944 : {
945 : // bad character ended up in the revision
946 4 : check_version(v.c_str(), last_error.str());
947 : }
948 : else
949 : {
950 7 : if(v.find_first_of(':', p + 1) == std::string::npos)
951 : {
952 7 : check_version(v.c_str(), last_error.str());
953 : }
954 : else
955 : {
956 : // a revision does not accept a ':' character and since
957 : // it is checked before the version we get that error
958 : // instead instead of the version error...
959 0 : check_version(v.c_str(), last_error.str());
960 : }
961 : }
962 : }
963 : }
964 : }
965 : }
966 : CATCH_END_SECTION()
967 :
968 14 : CATCH_START_SECTION("invalid_rpm_versions: max + 1 fails")
969 : {
970 2 : versiontheca::versiontheca::pointer_t a(create("4294967295.4294967295.4294967295"));
971 1 : CATCH_REQUIRE(a->is_valid());
972 1 : CATCH_REQUIRE_FALSE(a->next(2));
973 1 : CATCH_REQUIRE_FALSE(a->is_valid());
974 1 : CATCH_REQUIRE(a->get_last_error() == "maximum limit reached; cannot increment version any further.");
975 : }
976 : CATCH_END_SECTION()
977 :
978 14 : CATCH_START_SECTION("invalid_rpm_versions: min - 1 fails")
979 : {
980 2 : versiontheca::versiontheca::pointer_t a(create("0.0"));
981 1 : CATCH_REQUIRE(a->is_valid());
982 1 : CATCH_REQUIRE_FALSE(a->previous(2));
983 1 : CATCH_REQUIRE_FALSE(a->is_valid());
984 1 : CATCH_REQUIRE(a->get_last_error() == "minimum limit reached; cannot decrement version any further.");
985 : }
986 : CATCH_END_SECTION()
987 7 : }
988 :
989 :
990 10 : CATCH_TEST_CASE("bad_rpm_calls", "[invalid]")
991 : {
992 16 : CATCH_START_SECTION("bad_rpm_calls: next without a version")
993 : {
994 2 : versiontheca::rpm::pointer_t t(std::make_shared<versiontheca::rpm>());
995 2 : versiontheca::versiontheca v(t);
996 1 : CATCH_REQUIRE_FALSE(v.next(0));
997 1 : CATCH_REQUIRE(v.get_last_error() == "no parts in this RPM version; cannot compute upstream start/end.");
998 : }
999 : CATCH_END_SECTION()
1000 :
1001 16 : CATCH_START_SECTION("bad_rpm_calls: previous without a version")
1002 : {
1003 2 : versiontheca::rpm::pointer_t t(std::make_shared<versiontheca::rpm>());
1004 2 : versiontheca::versiontheca v(t);
1005 1 : CATCH_REQUIRE_FALSE(v.previous(0));
1006 1 : CATCH_REQUIRE(v.get_last_error() == "no parts in this RPM version; cannot compute upstream start/end.");
1007 : }
1008 : CATCH_END_SECTION()
1009 :
1010 16 : CATCH_START_SECTION("bad_rpm_calls: next out of bounds")
1011 : {
1012 2 : versiontheca::versiontheca::pointer_t a(create("1.5.3-r5"));
1013 101 : for(int p(-100); p < 0; ++p)
1014 : {
1015 100 : CATCH_REQUIRE_THROWS_MATCHES(
1016 : a->next(p)
1017 : , versiontheca::invalid_parameter
1018 : , Catch::Matchers::ExceptionMessage(
1019 : "versiontheca_exception: position calling next() cannot be a negative number."));
1020 : }
1021 101 : for(int p(versiontheca::MAX_PARTS); p < static_cast<int>(versiontheca::MAX_PARTS + 100); ++p)
1022 : {
1023 100 : CATCH_REQUIRE_THROWS_MATCHES(
1024 : a->next(p)
1025 : , versiontheca::invalid_parameter
1026 : , Catch::Matchers::ExceptionMessage(
1027 : "versiontheca_exception: position calling next() cannot be more than "
1028 : + std::to_string(versiontheca::MAX_PARTS)
1029 : + "."));
1030 : }
1031 : }
1032 : CATCH_END_SECTION()
1033 :
1034 16 : CATCH_START_SECTION("bad_rpm_calls: previous out of bounds")
1035 : {
1036 2 : versiontheca::versiontheca::pointer_t a(create("1.5.3-r5"));
1037 101 : for(int p(-100); p < 0; ++p)
1038 : {
1039 100 : CATCH_REQUIRE_THROWS_MATCHES(
1040 : a->previous(p)
1041 : , versiontheca::invalid_parameter
1042 : , Catch::Matchers::ExceptionMessage(
1043 : "versiontheca_exception: position calling previous() cannot be a negative number."));
1044 : }
1045 101 : for(int p(versiontheca::MAX_PARTS); p < static_cast<int>(versiontheca::MAX_PARTS + 100); ++p)
1046 : {
1047 100 : CATCH_REQUIRE_THROWS_MATCHES(
1048 : a->previous(p)
1049 : , versiontheca::invalid_parameter
1050 : , Catch::Matchers::ExceptionMessage(
1051 : "versiontheca_exception: position calling previous() cannot be more than "
1052 : + std::to_string(versiontheca::MAX_PARTS)
1053 : + "."));
1054 : }
1055 : }
1056 : CATCH_END_SECTION()
1057 :
1058 16 : CATCH_START_SECTION("bad_rpm_calls: resize out of bounds")
1059 : {
1060 2 : versiontheca::versiontheca::pointer_t a(create("1.5.3-r5"));
1061 100 : for(int p(versiontheca::MAX_PARTS + 1); p < static_cast<int>(versiontheca::MAX_PARTS + 100); ++p)
1062 : {
1063 99 : CATCH_REQUIRE_THROWS_MATCHES(
1064 : a->get_trait()->resize(p)
1065 : , versiontheca::invalid_parameter
1066 : , Catch::Matchers::ExceptionMessage(
1067 : "versiontheca_exception: requested too many parts."));
1068 : }
1069 : }
1070 : CATCH_END_SECTION()
1071 :
1072 16 : CATCH_START_SECTION("bad_rpm_calls: next/erase out of bounds")
1073 : {
1074 2 : versiontheca::versiontheca::pointer_t a(create("103:1.2.3.4.5-r5with6many8release9parts"));
1075 1 : CATCH_REQUIRE(a->size() == 15);
1076 1 : CATCH_REQUIRE_THROWS_MATCHES(
1077 : a->next(15) // too many because this checks total number while insert()-ing
1078 : , versiontheca::invalid_parameter
1079 : , Catch::Matchers::ExceptionMessage(
1080 : "versiontheca_exception: trying to insert more parts when maximum was already reached."));
1081 1 : CATCH_REQUIRE(a->size() == 25);
1082 11 : for(int i(0); i < 10; ++i)
1083 : {
1084 10 : a->get_trait()->erase(15);
1085 : }
1086 1 : CATCH_REQUIRE(a->size() == 15);
1087 1 : CATCH_REQUIRE_THROWS_MATCHES(
1088 : a->get_trait()->erase(15) // we have 15 left, trying to delete more will fail
1089 : , versiontheca::invalid_parameter
1090 : , Catch::Matchers::ExceptionMessage(
1091 : "versiontheca_exception: trying to erase a non-existant part."));
1092 31 : while(a->size() > 0)
1093 : {
1094 15 : a->get_trait()->resize(a->size() - 1);
1095 : }
1096 : }
1097 : CATCH_END_SECTION()
1098 :
1099 16 : CATCH_START_SECTION("bad_rpm_calls: compare against an empty (invalid) version")
1100 : {
1101 2 : versiontheca::versiontheca::pointer_t a(create("1.2"));
1102 2 : versiontheca::rpm::pointer_t t(std::make_shared<versiontheca::rpm>());
1103 2 : versiontheca::versiontheca empty(t, "");
1104 :
1105 1 : CATCH_REQUIRE(a->is_valid());
1106 1 : CATCH_REQUIRE_FALSE(empty.is_valid());
1107 :
1108 1 : CATCH_REQUIRE_THROWS_MATCHES(
1109 : a->compare(empty)
1110 : , versiontheca::invalid_version
1111 : , Catch::Matchers::ExceptionMessage(
1112 : "versiontheca_exception: one or both of the input versions are not valid."));
1113 :
1114 1 : CATCH_REQUIRE_THROWS_MATCHES(
1115 : a->get_trait()->compare(t)
1116 : , versiontheca::empty_version
1117 : , Catch::Matchers::ExceptionMessage(
1118 : "versiontheca_exception: one or both of the input versions are empty."));
1119 : }
1120 : CATCH_END_SECTION()
1121 :
1122 16 : CATCH_START_SECTION("bad_rpm_calls: compare using an empty (invalid) version")
1123 : {
1124 2 : versiontheca::rpm::pointer_t t(std::make_shared<versiontheca::rpm>());
1125 2 : versiontheca::versiontheca empty(t, "");
1126 2 : versiontheca::versiontheca::pointer_t b(create("5.3"));
1127 :
1128 1 : CATCH_REQUIRE_FALSE(empty.is_valid());
1129 1 : CATCH_REQUIRE(b->is_valid());
1130 :
1131 1 : CATCH_REQUIRE(empty.get_major() == 0);
1132 1 : CATCH_REQUIRE(empty.get_minor() == 0);
1133 1 : CATCH_REQUIRE(empty.get_patch() == 0);
1134 1 : CATCH_REQUIRE(empty.get_build() == 0);
1135 :
1136 1 : CATCH_REQUIRE_THROWS_MATCHES(
1137 : empty.compare(*b)
1138 : , versiontheca::invalid_version
1139 : , Catch::Matchers::ExceptionMessage(
1140 : "versiontheca_exception: one or both of the input versions are not valid."));
1141 :
1142 1 : CATCH_REQUIRE_THROWS_MATCHES(
1143 : t->compare(b->get_trait())
1144 : , versiontheca::empty_version
1145 : , Catch::Matchers::ExceptionMessage(
1146 : "versiontheca_exception: one or both of the input versions are empty."));
1147 : }
1148 : CATCH_END_SECTION()
1149 14 : }
1150 :
1151 :
1152 :
1153 : // vim: ts=4 sw=4 et
|