Line data Source code
1 : // Copyright (c) 2006-2025 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/advgetopt
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 2 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 along
17 : // with this program; if not, write to the Free Software Foundation, Inc.,
18 : // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 :
20 : // advgetopt
21 : //
22 : #include <advgetopt/validator_duration.h>
23 : #include <advgetopt/validator_size.h>
24 :
25 : #include <advgetopt/exception.h>
26 :
27 :
28 : // self
29 : //
30 : #include "catch_main.h"
31 :
32 :
33 : // snapdev
34 : //
35 : #include <snapdev/math.h>
36 : #include <snapdev/ostream_int128.h>
37 :
38 :
39 : // C++
40 : //
41 : #include <cmath>
42 : #include <fstream>
43 : #include <iomanip>
44 :
45 :
46 : // last include
47 : //
48 : #include <snapdev/poison.h>
49 :
50 :
51 :
52 : namespace
53 : {
54 :
55 : struct duration_t
56 : {
57 : char const * const f_suffix = nullptr;
58 : double f_factor = 1.0;
59 : };
60 :
61 : constexpr duration_t const g_duration_suffixes[] =
62 : {
63 : { "", 1.0 },
64 : { "s", 1.0 },
65 : { "second", 1.0 },
66 : { "seconds", 1.0 },
67 :
68 : { "m", -1.0 }, // may represent minutes or months
69 : { "minute", 60.0 },
70 : { "minutes", 60.0 },
71 :
72 : { "h", 3600.0 },
73 : { "hour", 3600.0 },
74 : { "hours", 3600.0 },
75 :
76 : { "d", 86400.0 },
77 : { "day", 86400.0 },
78 : { "days", 86400.0 },
79 :
80 : { "w", 86400.0 * 7.0 },
81 : { "week", 86400.0 * 7.0 },
82 : { "weeks", 86400.0 * 7.0 },
83 :
84 : { "month", 86400.0 * 30.0 },
85 : { "months", 86400.0 * 30.0 },
86 :
87 : { "y", 86400.0 * 365.0 },
88 : { "year", 86400.0 * 365.0 },
89 : { "years", 86400.0 * 365.0 },
90 : };
91 :
92 : struct size_suffix_t
93 : {
94 : char const * const f_suffix = nullptr;
95 : int f_base = 1000.0;
96 : int f_power = 0.0;
97 : };
98 :
99 : constexpr size_suffix_t const g_size_suffixes[] =
100 : {
101 : { "", 1000, 0 },
102 : { "B", 1000, 0 },
103 :
104 : { "kB", 1000, 1 },
105 : { "KiB", 1024, 1 },
106 :
107 : { "MB", 1000, 2 },
108 : { "MiB", 1024, 2 },
109 :
110 : { "GB", 1000, 3 },
111 : { "GiB", 1024, 3 },
112 :
113 : { "TB", 1000, 4 },
114 : { "TiB", 1024, 4 },
115 :
116 : { "PB", 1000, 5 },
117 : { "PiB", 1024, 5 },
118 :
119 : { "EB", 1000, 6 },
120 : { "EiB", 1024, 6 },
121 :
122 : { "ZB", 1000, 7 },
123 : { "ZiB", 1024, 7 },
124 :
125 : { "YB", 1000, 8 },
126 : { "YiB", 1024, 8 },
127 :
128 : { "RB", 1000, 9 },
129 : { "RiB", 1024, 9 },
130 :
131 : { "QB", 1000, 10 },
132 : { "QiB", 1024, 10 },
133 : };
134 :
135 123768 : std::int64_t large_rnd(bool zero_allowed = true)
136 : {
137 : for(;;)
138 : {
139 123768 : std::int64_t const result((static_cast<std::int64_t>(rand()) << 0)
140 123768 : ^ (static_cast<std::int64_t>(rand()) << 16)
141 123768 : ^ (static_cast<std::int64_t>(rand()) << 32)
142 123768 : ^ (static_cast<std::int64_t>(rand()) << 48));
143 123768 : if(result != 0
144 0 : || zero_allowed)
145 : {
146 123768 : return result;
147 : }
148 0 : }
149 : }
150 :
151 : }
152 :
153 :
154 :
155 2 : CATCH_TEST_CASE("unknown_validator", "[validator][valid][validation]")
156 : {
157 2 : CATCH_START_SECTION("unknown_validator: undefined validator")
158 : {
159 : // this is a valid case, it does not throw, it just returns a nullptr
160 : //
161 3 : CATCH_REQUIRE(advgetopt::validator::create("unknown", advgetopt::string_list_t()) == nullptr);
162 : }
163 2 : CATCH_END_SECTION()
164 :
165 2 : CATCH_START_SECTION("unknown_validator: empty string")
166 : {
167 1 : CATCH_REQUIRE(advgetopt::validator::create(std::string()) == nullptr);
168 : }
169 2 : CATCH_END_SECTION()
170 2 : }
171 :
172 :
173 :
174 3 : CATCH_TEST_CASE("email_validator", "[invalid][validation]")
175 : {
176 3 : CATCH_START_SECTION("email_validator: verify that email verification works.")
177 : {
178 3 : advgetopt::validator::pointer_t email(advgetopt::validator::create("email"));
179 :
180 1 : CATCH_REQUIRE(email != nullptr);
181 1 : CATCH_REQUIRE(email->name() == "email");
182 :
183 3 : CATCH_REQUIRE_FALSE(email->validate(""));
184 3 : CATCH_REQUIRE(email->validate("user@example.com"));
185 3 : CATCH_REQUIRE(email->validate("USER@EXAMPLE.COM"));
186 3 : CATCH_REQUIRE_FALSE(email->validate("user1@example.com, user2@example.com, user3@example.com"));
187 3 : CATCH_REQUIRE_FALSE(email->validate("User!example.com"));
188 3 : CATCH_REQUIRE_FALSE(email->validate("@example.com"));
189 3 : CATCH_REQUIRE_FALSE(email->validate("uSeR@"));
190 3 : CATCH_REQUIRE_FALSE(email->validate("uSeR@com"));
191 1 : }
192 3 : CATCH_END_SECTION()
193 :
194 3 : CATCH_START_SECTION("email_validator: verify that one email verification works (single explicitly).")
195 : {
196 3 : advgetopt::validator::pointer_t email(advgetopt::validator::create("email(single)"));
197 :
198 1 : CATCH_REQUIRE(email != nullptr);
199 1 : CATCH_REQUIRE(email->name() == "email");
200 :
201 3 : CATCH_REQUIRE_FALSE(email->validate(""));
202 3 : CATCH_REQUIRE(email->validate("user@example.com"));
203 3 : CATCH_REQUIRE(email->validate("USER@EXAMPLE.COM"));
204 3 : CATCH_REQUIRE_FALSE(email->validate("user1@example.com, user2@example.com, user3@example.com"));
205 3 : CATCH_REQUIRE_FALSE(email->validate("User!example.com"));
206 3 : CATCH_REQUIRE_FALSE(email->validate("@example.com"));
207 3 : CATCH_REQUIRE_FALSE(email->validate("uSeR@"));
208 3 : CATCH_REQUIRE_FALSE(email->validate("uSeR@com"));
209 1 : }
210 3 : CATCH_END_SECTION()
211 :
212 3 : CATCH_START_SECTION("email_validator: verify that multiple emails verification works.")
213 : {
214 3 : advgetopt::validator::pointer_t email(advgetopt::validator::create("email(multiple)"));
215 :
216 1 : CATCH_REQUIRE(email != nullptr);
217 1 : CATCH_REQUIRE(email->name() == "email");
218 :
219 3 : CATCH_REQUIRE_FALSE(email->validate(""));
220 3 : CATCH_REQUIRE(email->validate("user1@example.com, user2@example.com, user3@example.com"));
221 3 : CATCH_REQUIRE(email->validate("USER@EXAMPLE.COM"));
222 3 : CATCH_REQUIRE_FALSE(email->validate("User!example.com"));
223 3 : CATCH_REQUIRE_FALSE(email->validate("@example.com"));
224 3 : CATCH_REQUIRE_FALSE(email->validate("uSeR@"));
225 3 : CATCH_REQUIRE_FALSE(email->validate("uSeR@com"));
226 1 : }
227 3 : CATCH_END_SECTION()
228 3 : }
229 :
230 :
231 :
232 3 : CATCH_TEST_CASE("integer_validator", "[validator][valid][validation]")
233 : {
234 3 : CATCH_START_SECTION("integer_validator: verify the integer validator")
235 : {
236 3 : advgetopt::validator::pointer_t integer_validator(advgetopt::validator::create("integer", advgetopt::string_list_t()));
237 :
238 1 : CATCH_REQUIRE(integer_validator != nullptr);
239 1 : CATCH_REQUIRE(integer_validator->name() == "integer");
240 :
241 3 : CATCH_REQUIRE_FALSE(integer_validator->validate(""));
242 3 : CATCH_REQUIRE_FALSE(integer_validator->validate("+"));
243 3 : CATCH_REQUIRE_FALSE(integer_validator->validate("-"));
244 :
245 1001 : for(int idx(0); idx < 1000; ++idx)
246 : {
247 1000 : std::int64_t value(large_rnd());
248 1000 : std::string const v(std::to_string(value));
249 :
250 1000 : CATCH_REQUIRE(integer_validator->validate(v));
251 :
252 1000 : if(value >= 0)
253 : {
254 497 : CATCH_REQUIRE(integer_validator->validate('+' + v));
255 : }
256 :
257 1000 : std::string const space_before(' ' + v);
258 1000 : CATCH_REQUIRE_FALSE(integer_validator->validate(space_before));
259 :
260 1000 : std::string const space_after(v + ' ');
261 1000 : CATCH_REQUIRE_FALSE(integer_validator->validate(space_after));
262 :
263 1000 : std::string const before(static_cast<char>(rand() % 26 + 'a') + v);
264 1000 : CATCH_REQUIRE_FALSE(integer_validator->validate(before));
265 :
266 1000 : std::string const after(v + static_cast<char>(rand() % 26 + 'a'));
267 1000 : CATCH_REQUIRE_FALSE(integer_validator->validate(after));
268 1000 : }
269 :
270 : // max number
271 3 : CATCH_REQUIRE(integer_validator->validate("9223372036854775807"));
272 3 : CATCH_REQUIRE(integer_validator->validate("+9223372036854775807"));
273 :
274 : // overflow
275 3 : CATCH_REQUIRE_FALSE(integer_validator->validate("9223372036854775808"));
276 3 : CATCH_REQUIRE_FALSE(integer_validator->validate("+9223372036854775808"));
277 :
278 : // min number
279 3 : CATCH_REQUIRE(integer_validator->validate("-9223372036854775808"));
280 :
281 : // underflow
282 3 : CATCH_REQUIRE_FALSE(integer_validator->validate("-9223372036854775809"));
283 :
284 : // too many digits
285 3 : CATCH_REQUIRE_FALSE(integer_validator->validate("92233720368547758091"));
286 3 : CATCH_REQUIRE_FALSE(integer_validator->validate("+92233720368547758092"));
287 3 : CATCH_REQUIRE_FALSE(integer_validator->validate("-92233720368547758093"));
288 1 : }
289 3 : CATCH_END_SECTION()
290 :
291 3 : CATCH_START_SECTION("integer_validator: verify the integer ranges")
292 : {
293 1 : bool had_standalone(false);
294 21 : for(int count(0); count < 20 || !had_standalone; ++count)
295 : {
296 20 : std::int64_t min(large_rnd());
297 20 : std::int64_t max(large_rnd());
298 20 : if(min > max)
299 : {
300 7 : std::swap(min, max);
301 : }
302 :
303 20 : std::string const & smin(std::to_string(min));
304 20 : std::string const & smax(std::to_string(max));
305 :
306 60 : std::string range("...");
307 80 : for(int three(0); three < 3; ++three)
308 : {
309 60 : if(rand() % 5 == 0)
310 : {
311 10 : range = ' ' + range;
312 : }
313 60 : if(rand() % 5 == 0)
314 : {
315 16 : range = range + ' ';
316 : }
317 : }
318 20 : range = smin + range + smax;
319 80 : for(int three(0); three < 3; ++three)
320 : {
321 60 : if(rand() % 5 == 0)
322 : {
323 11 : range = ' ' + range;
324 : }
325 60 : if(rand() % 5 == 0)
326 : {
327 15 : range = range + ' ';
328 : }
329 : }
330 :
331 20 : std::int64_t standalone(0);
332 20 : bool standalone_included(rand() % 4 == 0);
333 20 : if(standalone_included)
334 : {
335 5 : if(min == std::numeric_limits<std::int64_t>::min()
336 5 : && max == std::numeric_limits<std::int64_t>::max())
337 : {
338 0 : standalone_included = false;
339 : }
340 : else
341 : {
342 5 : had_standalone = true;
343 : do
344 : {
345 5 : standalone = large_rnd();
346 : }
347 5 : while(standalone >= min && standalone <= max);
348 :
349 15 : std::string sep(",");
350 5 : if(rand() % 3 == 0)
351 : {
352 2 : sep = ' ' + sep;
353 : }
354 5 : if(rand() % 3 == 0)
355 : {
356 1 : sep = sep + ' ';
357 : }
358 5 : if(rand() % 2 == 0)
359 : {
360 1 : range = std::to_string(standalone) + "," + range;
361 : }
362 : else
363 : {
364 4 : range = range + "," + std::to_string(standalone);
365 : }
366 5 : }
367 : }
368 20 : advgetopt::string_list_t range_list;
369 60 : advgetopt::split_string(range
370 : , range_list
371 : , {","});
372 60 : advgetopt::validator::pointer_t integer_validator(advgetopt::validator::create("integer", range_list));
373 :
374 20 : CATCH_REQUIRE(integer_validator != nullptr);
375 20 : CATCH_REQUIRE(integer_validator->name() == "integer");
376 :
377 20020 : for(int idx(0); idx < 1000; ++idx)
378 : {
379 20000 : std::int64_t value(large_rnd());
380 :
381 : // force valid values otherwise we're likely to only have
382 : // invalid ones
383 : //
384 20000 : if(idx % 10 == 0)
385 : {
386 2000 : value %= max - min + 1;
387 2000 : value += min;
388 : }
389 18000 : else if(idx % 50 == 1 && standalone_included)
390 : {
391 100 : value = standalone;
392 : }
393 :
394 20000 : std::string const v(std::to_string(value));
395 :
396 20000 : if((standalone_included && value == standalone)
397 19900 : || (value >= min && value <= max))
398 : {
399 6533 : CATCH_REQUIRE(integer_validator->validate(v));
400 6533 : }
401 : else
402 : {
403 13467 : CATCH_REQUIRE_FALSE(integer_validator->validate(v));
404 : }
405 :
406 20000 : if(value >= 0)
407 : {
408 10057 : if((standalone_included && value == standalone)
409 9977 : || (value >= min && value <= max))
410 : {
411 3246 : CATCH_REQUIRE(integer_validator->validate('+' + v));
412 3246 : }
413 : else
414 : {
415 6811 : CATCH_REQUIRE_FALSE(integer_validator->validate('+' + v));
416 : }
417 : }
418 :
419 20000 : std::string const space_before(' ' + v);
420 20000 : CATCH_REQUIRE_FALSE(integer_validator->validate(space_before));
421 :
422 20000 : std::string const space_after(v + ' ');
423 20000 : CATCH_REQUIRE_FALSE(integer_validator->validate(space_after));
424 :
425 20000 : std::string const before(static_cast<char>(rand() % 26 + 'a') + v);
426 20000 : CATCH_REQUIRE_FALSE(integer_validator->validate(before));
427 :
428 20000 : std::string const after(v + static_cast<char>(rand() % 26 + 'a'));
429 20000 : CATCH_REQUIRE_FALSE(integer_validator->validate(after));
430 20000 : }
431 20 : }
432 : }
433 3 : CATCH_END_SECTION()
434 :
435 3 : CATCH_START_SECTION("integer_validator: verify the integer standalone list")
436 : {
437 21 : for(int count(0); count < 20; ++count)
438 : {
439 20 : int valid(rand() % 10 + 5);
440 20 : std::vector<std::int64_t> numbers;
441 20 : numbers.reserve(valid);
442 20 : std::string standalone_values;
443 207 : for(int idx(0); idx < valid; ++idx)
444 : {
445 187 : std::int64_t const value(large_rnd());
446 187 : numbers.push_back(value);
447 187 : std::string const & svalue(std::to_string(value));
448 187 : if(rand() % 5 == 0)
449 : {
450 25 : standalone_values += ' ';
451 : }
452 187 : if(idx != 0)
453 : {
454 167 : standalone_values += ',';
455 : }
456 187 : if(rand() % 5 == 0)
457 : {
458 39 : standalone_values += ' ';
459 : }
460 187 : standalone_values += svalue;
461 187 : }
462 20 : if(rand() % 5 == 0)
463 : {
464 8 : standalone_values += ' ';
465 : }
466 20 : advgetopt::string_list_t range_list;
467 60 : advgetopt::split_string(standalone_values
468 : , range_list
469 : , {","});
470 :
471 60 : advgetopt::validator::pointer_t integer_validator(advgetopt::validator::create("integer", range_list));
472 :
473 20 : CATCH_REQUIRE(integer_validator != nullptr);
474 20 : CATCH_REQUIRE(integer_validator->name() == "integer");
475 :
476 207 : for(size_t idx(0); idx < numbers.size(); ++idx)
477 : {
478 187 : std::string const svalue(std::to_string(numbers[idx]));
479 :
480 187 : CATCH_REQUIRE(integer_validator->validate(svalue));
481 187 : }
482 :
483 20020 : for(int idx(0); idx < 1000; ++idx)
484 : {
485 20000 : std::int64_t value;
486 :
487 : for(;;)
488 : {
489 20000 : value = large_rnd();
490 20000 : if(std::find(numbers.begin(), numbers.end(), value) == numbers.end())
491 : {
492 20000 : break;
493 : }
494 : }
495 :
496 20000 : CATCH_REQUIRE_FALSE(integer_validator->validate(std::to_string(value)));
497 : }
498 20 : }
499 : }
500 3 : CATCH_END_SECTION()
501 3 : }
502 :
503 :
504 :
505 :
506 3 : CATCH_TEST_CASE("length_validator", "[validator][valid][validation]")
507 : {
508 3 : CATCH_START_SECTION("length_validator: verify the length validator")
509 : {
510 3 : advgetopt::validator::pointer_t length_validator(advgetopt::validator::create("length", advgetopt::string_list_t()));
511 :
512 1 : CATCH_REQUIRE(length_validator != nullptr);
513 1 : CATCH_REQUIRE(length_validator->name() == "length");
514 :
515 3 : CATCH_REQUIRE(length_validator->validate("Anything works in this case"));
516 3 : CATCH_REQUIRE(length_validator->validate("since the length won't be checked"));
517 3 : CATCH_REQUIRE(length_validator->validate(""));
518 3 : CATCH_REQUIRE(length_validator->validate("even an empty string"));
519 1 : }
520 3 : CATCH_END_SECTION()
521 :
522 3 : CATCH_START_SECTION("length_validator: verify the length ranges")
523 : {
524 1 : bool had_standalone(false);
525 21 : for(int count(0); count < 20 || !had_standalone; ++count)
526 : {
527 20 : std::uint64_t min(rand() % 25 + 5);
528 20 : std::uint64_t max(rand() % 25 + 5);
529 20 : if(min > max)
530 : {
531 12 : std::swap(min, max);
532 : }
533 :
534 20 : std::string const & smin(std::to_string(min));
535 20 : std::string const & smax(std::to_string(max));
536 :
537 60 : std::string range("...");
538 80 : for(int three(0); three < 3; ++three)
539 : {
540 60 : if(rand() % 5 == 0)
541 : {
542 14 : range = ' ' + range;
543 : }
544 60 : if(rand() % 5 == 0)
545 : {
546 7 : range = range + ' ';
547 : }
548 : }
549 20 : range = smin + range + smax;
550 80 : for(int three(0); three < 3; ++three)
551 : {
552 60 : if(rand() % 5 == 0)
553 : {
554 7 : range = ' ' + range;
555 : }
556 60 : if(rand() % 5 == 0)
557 : {
558 11 : range = range + ' ';
559 : }
560 : }
561 :
562 20 : std::uint64_t standalone(0);
563 20 : bool const standalone_included(rand() % 4 == 0);
564 20 : if(standalone_included)
565 : {
566 5 : had_standalone = true;
567 : do
568 : {
569 9 : standalone = rand() % 35;
570 : }
571 9 : while(standalone >= min && standalone <= max);
572 :
573 15 : std::string sep(",");
574 5 : if(rand() % 3 == 0)
575 : {
576 1 : sep = ' ' + sep;
577 : }
578 5 : if(rand() % 3 == 0)
579 : {
580 2 : sep = sep + ' ';
581 : }
582 5 : if(rand() % 2 == 0)
583 : {
584 2 : range = std::to_string(standalone) + "," + range;
585 : }
586 : else
587 : {
588 3 : range = range + "," + std::to_string(standalone);
589 : }
590 5 : }
591 20 : advgetopt::string_list_t range_list;
592 60 : advgetopt::split_string(range
593 : , range_list
594 : , {","});
595 60 : advgetopt::validator::pointer_t length_validator(advgetopt::validator::create("length", range_list));
596 :
597 20 : CATCH_REQUIRE(length_validator != nullptr);
598 20 : CATCH_REQUIRE(length_validator->name() == "length");
599 :
600 590 : for(std::size_t idx(0); idx < std::max(max, standalone) + 5; ++idx)
601 : {
602 570 : std::string value;
603 8855 : for(std::size_t n(0); n < idx; ++n)
604 : {
605 8285 : value += rand() % 26 + 'a';
606 : }
607 :
608 174 : if((standalone_included && value.length() == standalone)
609 744 : || (value.length() >= min && value.length() <= max))
610 : {
611 157 : CATCH_REQUIRE(length_validator->validate(value));
612 : }
613 : else
614 : {
615 413 : CATCH_REQUIRE_FALSE(length_validator->validate(value));
616 : }
617 570 : }
618 20 : }
619 : }
620 3 : CATCH_END_SECTION()
621 :
622 3 : CATCH_START_SECTION("length_validator: verify the length standalone list")
623 : {
624 21 : for(int count(0); count < 20; ++count)
625 : {
626 20 : int valid(rand() % 10 + 5);
627 20 : std::vector<std::uint64_t> string_lengths;
628 20 : string_lengths.reserve(valid);
629 20 : std::string standalone_lengths;
630 184 : for(int idx(0); idx < valid; ++idx)
631 : {
632 164 : std::int64_t const length(rand() % 25 + 5);
633 164 : string_lengths.push_back(length);
634 164 : std::string const & slength(std::to_string(length));
635 164 : if(rand() % 5 == 0)
636 : {
637 37 : standalone_lengths += ' ';
638 : }
639 164 : if(idx != 0)
640 : {
641 144 : standalone_lengths += ',';
642 : }
643 164 : if(rand() % 5 == 0)
644 : {
645 32 : standalone_lengths += ' ';
646 : }
647 164 : standalone_lengths += slength;
648 164 : }
649 20 : if(rand() % 5 == 0)
650 : {
651 2 : standalone_lengths += ' ';
652 : }
653 20 : advgetopt::string_list_t range_list;
654 60 : advgetopt::split_string(standalone_lengths
655 : , range_list
656 : , {","});
657 :
658 60 : advgetopt::validator::pointer_t length_validator(advgetopt::validator::create("length", range_list));
659 :
660 20 : CATCH_REQUIRE(length_validator != nullptr);
661 20 : CATCH_REQUIRE(length_validator->name() == "length");
662 :
663 184 : for(std::size_t idx(0); idx < string_lengths.size(); ++idx)
664 : {
665 164 : std::string value;
666 2925 : for(std::uint64_t n(0); n < string_lengths[idx]; ++n)
667 : {
668 2761 : value += rand() % 26 + 'a';
669 : }
670 164 : CATCH_REQUIRE(length_validator->validate(value));
671 164 : }
672 :
673 20 : std::size_t const longest(*std::max_element(string_lengths.begin(), string_lengths.end()));
674 666 : for(std::size_t idx(0); idx <= longest + 5; ++idx)
675 : {
676 646 : if(std::find(string_lengths.begin(), string_lengths.end(), idx) != string_lengths.end())
677 : {
678 141 : continue;
679 : }
680 :
681 505 : std::string value;
682 8380 : for(std::size_t n(0); n < idx; ++n)
683 : {
684 7875 : value += rand() % 26 + 'a';
685 : }
686 :
687 505 : CATCH_REQUIRE_FALSE(length_validator->validate(value));
688 505 : }
689 20 : }
690 : }
691 3 : CATCH_END_SECTION()
692 3 : }
693 :
694 :
695 :
696 :
697 1 : CATCH_TEST_CASE("multi_validators", "[validator][valid][validation]")
698 : {
699 1 : CATCH_START_SECTION("multi_validators: verify an integer along a few keywords")
700 : {
701 3 : advgetopt::validator::pointer_t list_validator(advgetopt::validator::create("keywords(off,min,max) | integer(1...100)"));
702 :
703 1 : CATCH_REQUIRE(list_validator != nullptr);
704 1 : CATCH_REQUIRE(list_validator->name() == "list");
705 :
706 3 : CATCH_REQUIRE(list_validator->validate("off"));
707 3 : CATCH_REQUIRE(list_validator->validate("min"));
708 3 : CATCH_REQUIRE(list_validator->validate("max"));
709 :
710 122 : for(int idx(-10); idx <= 110; ++idx)
711 : {
712 121 : std::string const v(std::to_string(idx));
713 :
714 121 : if(idx < 1 || idx > 100)
715 : {
716 21 : CATCH_REQUIRE_FALSE(list_validator->validate(v));
717 21 : }
718 : else
719 : {
720 100 : CATCH_REQUIRE(list_validator->validate(v));
721 : }
722 121 : }
723 1 : }
724 1 : CATCH_END_SECTION()
725 1 : }
726 :
727 :
728 :
729 1 : CATCH_TEST_CASE("keywords_validator", "[validator][valid][validation]")
730 : {
731 1 : CATCH_START_SECTION("keywords_validator: verify simple keywords")
732 : {
733 3 : advgetopt::validator::pointer_t list_validator(advgetopt::validator::create("keywords(angle, corner ,, ceiling)"));
734 :
735 1 : CATCH_REQUIRE(list_validator != nullptr);
736 1 : CATCH_REQUIRE(list_validator->name() == "keywords");
737 :
738 3 : CATCH_REQUIRE(list_validator->validate("angle"));
739 3 : CATCH_REQUIRE(list_validator->validate("corner"));
740 3 : CATCH_REQUIRE(list_validator->validate("ceiling"));
741 :
742 3 : CATCH_REQUIRE_FALSE(list_validator->validate(""));
743 3 : CATCH_REQUIRE_FALSE(list_validator->validate("other"));
744 1 : }
745 1 : CATCH_END_SECTION()
746 1 : }
747 :
748 :
749 :
750 :
751 3 : CATCH_TEST_CASE("double_validator", "[validator][valid][validation]")
752 : {
753 3 : CATCH_START_SECTION("double_validator: verify the double validator")
754 : {
755 3 : advgetopt::validator::pointer_t double_validator(advgetopt::validator::create("double", advgetopt::string_list_t()));
756 :
757 1 : CATCH_REQUIRE(double_validator != nullptr);
758 1 : CATCH_REQUIRE(double_validator->name() == "double");
759 :
760 3 : CATCH_REQUIRE_FALSE(double_validator->validate(""));
761 3 : CATCH_REQUIRE_FALSE(double_validator->validate("+"));
762 3 : CATCH_REQUIRE_FALSE(double_validator->validate("-"));
763 3 : CATCH_REQUIRE_FALSE(double_validator->validate("alpha"));
764 :
765 1001 : for(int idx(0); idx < 1000; ++idx)
766 : {
767 1000 : double value(static_cast<double>(large_rnd()) / static_cast<double>(large_rnd(false)));
768 1000 : std::string const v(std::to_string(value));
769 :
770 1000 : CATCH_REQUIRE(double_validator->validate(v));
771 :
772 1000 : if(value >= 0)
773 : {
774 485 : CATCH_REQUIRE(double_validator->validate('+' + v));
775 : }
776 :
777 1000 : std::string const space_before(' ' + v);
778 1000 : CATCH_REQUIRE_FALSE(double_validator->validate(space_before));
779 :
780 1000 : std::string const space_after(v + ' ');
781 1000 : CATCH_REQUIRE_FALSE(double_validator->validate(space_after));
782 :
783 1000 : std::string const before(static_cast<char>(rand() % 26 + 'a') + v);
784 1000 : CATCH_REQUIRE_FALSE(double_validator->validate(before));
785 :
786 1000 : std::string const after(v + static_cast<char>(rand() % 26 + 'a'));
787 1000 : CATCH_REQUIRE_FALSE(double_validator->validate(after));
788 1000 : }
789 1 : }
790 3 : CATCH_END_SECTION()
791 :
792 3 : CATCH_START_SECTION("double_validator: verify the double ranges")
793 : {
794 1 : bool had_standalone(false);
795 21 : for(int count(0); count < 20 || !had_standalone; ++count)
796 : {
797 20 : double min(static_cast<double>(large_rnd()) / static_cast<double>(large_rnd(false)));
798 20 : double max(static_cast<double>(large_rnd()) / static_cast<double>(large_rnd(false)));
799 20 : if(min > max)
800 : {
801 9 : std::swap(min, max);
802 : }
803 :
804 20 : std::string const & smin(std::to_string(min));
805 20 : std::string const & smax(std::to_string(max));
806 :
807 60 : std::string range("...");
808 80 : for(int three(0); three < 3; ++three)
809 : {
810 60 : if(rand() % 5 == 0)
811 : {
812 12 : range = ' ' + range;
813 : }
814 60 : if(rand() % 5 == 0)
815 : {
816 11 : range = range + ' ';
817 : }
818 : }
819 20 : range = smin + range + smax;
820 80 : for(int three(0); three < 3; ++three)
821 : {
822 60 : if(rand() % 5 == 0)
823 : {
824 10 : range = ' ' + range;
825 : }
826 60 : if(rand() % 5 == 0)
827 : {
828 13 : range = range + ' ';
829 : }
830 : }
831 :
832 20 : double standalone(0);
833 20 : bool standalone_included(rand() % 4 == 0);
834 20 : if(standalone_included)
835 : {
836 7 : if(min <= std::numeric_limits<double>::min()
837 7 : && max >= std::numeric_limits<double>::max())
838 : {
839 0 : standalone_included = false;
840 : }
841 : else
842 : {
843 7 : had_standalone = true;
844 : do
845 : {
846 23 : standalone = static_cast<double>(large_rnd()) / static_cast<double>(large_rnd(false));
847 : }
848 23 : while(standalone >= min && standalone <= max);
849 :
850 21 : std::string sep(",");
851 7 : if(rand() % 3 == 0)
852 : {
853 1 : sep = ' ' + sep;
854 : }
855 7 : if(rand() % 3 == 0)
856 : {
857 2 : sep = sep + ' ';
858 : }
859 7 : if(rand() % 2 == 0)
860 : {
861 2 : range = std::to_string(standalone) + "," + range;
862 : }
863 : else
864 : {
865 5 : range = range + "," + std::to_string(standalone);
866 : }
867 7 : }
868 : }
869 20 : advgetopt::string_list_t range_list;
870 60 : advgetopt::split_string(range
871 : , range_list
872 : , {","});
873 60 : advgetopt::validator::pointer_t double_validator(advgetopt::validator::create("double", range_list));
874 :
875 20 : CATCH_REQUIRE(double_validator != nullptr);
876 20 : CATCH_REQUIRE(double_validator->name() == "double");
877 :
878 20020 : for(int idx(0); idx < 1000; ++idx)
879 : {
880 20000 : double value(static_cast<double>(large_rnd()) / static_cast<double>(large_rnd(false)));
881 :
882 : // force valid values otherwise we're likely to only have
883 : // invalid ones
884 : //
885 20000 : if(idx % 10 == 0)
886 : {
887 2000 : value = fmod(value, max - min + 1.0) + min;
888 : }
889 18000 : else if(idx % 50 == 1 && standalone_included)
890 : {
891 140 : value = standalone;
892 : }
893 :
894 20000 : std::string const v(std::to_string(value));
895 :
896 : #pragma GCC diagnostic push
897 : #pragma GCC diagnostic ignored "-Wfloat-equal"
898 20000 : if((standalone_included && value == standalone)
899 19860 : || (value >= min && value <= max))
900 : {
901 7692 : CATCH_REQUIRE(double_validator->validate(v));
902 7692 : }
903 : else
904 : {
905 12308 : CATCH_REQUIRE_FALSE(double_validator->validate(v));
906 : }
907 :
908 20000 : if(value >= 0.0)
909 : {
910 9775 : if((standalone_included && value == standalone)
911 9715 : || (value >= min && value <= max))
912 : {
913 4357 : CATCH_REQUIRE(double_validator->validate('+' + v));
914 4357 : }
915 : else
916 : {
917 5418 : CATCH_REQUIRE_FALSE(double_validator->validate('+' + v));
918 : }
919 : }
920 : #pragma GCC diagnostic pop
921 :
922 20000 : std::string const space_before(' ' + v);
923 20000 : CATCH_REQUIRE_FALSE(double_validator->validate(space_before));
924 :
925 20000 : std::string const space_after(v + ' ');
926 20000 : CATCH_REQUIRE_FALSE(double_validator->validate(space_after));
927 :
928 20000 : std::string const before(static_cast<char>(rand() % 26 + 'a') + v);
929 20000 : CATCH_REQUIRE_FALSE(double_validator->validate(before));
930 :
931 20000 : std::string const after(v + static_cast<char>(rand() % 26 + 'a'));
932 20000 : CATCH_REQUIRE_FALSE(double_validator->validate(after));
933 20000 : }
934 20 : }
935 : }
936 3 : CATCH_END_SECTION()
937 :
938 3 : CATCH_START_SECTION("double_validator: verify the double standalone list")
939 : {
940 21 : for(int count(0); count < 20; ++count)
941 : {
942 20 : int valid(rand() % 10 + 5);
943 20 : std::vector<double> numbers;
944 20 : numbers.reserve(valid);
945 20 : std::string standalone_values;
946 225 : for(int idx(0); idx < valid; ++idx)
947 : {
948 205 : double const value(static_cast<double>(large_rnd()) / static_cast<double>(large_rnd(false)));
949 205 : numbers.push_back(value);
950 205 : std::string const & svalue(std::to_string(value));
951 205 : if(rand() % 5 == 0)
952 : {
953 38 : standalone_values += ' ';
954 : }
955 205 : if(idx != 0)
956 : {
957 185 : standalone_values += ',';
958 : }
959 205 : if(rand() % 5 == 0)
960 : {
961 49 : standalone_values += ' ';
962 : }
963 205 : standalone_values += svalue;
964 205 : }
965 20 : if(rand() % 5 == 0)
966 : {
967 3 : standalone_values += ' ';
968 : }
969 20 : advgetopt::string_list_t range_list;
970 60 : advgetopt::split_string(standalone_values
971 : , range_list
972 : , {","});
973 :
974 60 : advgetopt::validator::pointer_t double_validator(advgetopt::validator::create("double", range_list));
975 :
976 20 : CATCH_REQUIRE(double_validator != nullptr);
977 20 : CATCH_REQUIRE(double_validator->name() == "double");
978 :
979 225 : for(size_t idx(0); idx < numbers.size(); ++idx)
980 : {
981 205 : std::string const svalue(std::to_string(numbers[idx]));
982 :
983 205 : CATCH_REQUIRE(double_validator->validate(svalue));
984 205 : }
985 :
986 20020 : for(int idx(0); idx < 1000; ++idx)
987 : {
988 20000 : std::int64_t value;
989 :
990 : for(;;)
991 : {
992 20000 : value = static_cast<double>(large_rnd()) / static_cast<double>(large_rnd(false));
993 20000 : if(std::find(numbers.begin(), numbers.end(), value) == numbers.end())
994 : {
995 20000 : break;
996 : }
997 : }
998 :
999 20000 : CATCH_REQUIRE_FALSE(double_validator->validate(std::to_string(value)));
1000 : }
1001 20 : }
1002 : }
1003 3 : CATCH_END_SECTION()
1004 3 : }
1005 :
1006 :
1007 :
1008 :
1009 4 : CATCH_TEST_CASE("duration_validator", "[validator][valid][validation]")
1010 : {
1011 4 : CATCH_START_SECTION("duration_validator: verify the duration validator (simple values)")
1012 : {
1013 1 : double duration(0.0);
1014 :
1015 : // simple seconds with decimal point
1016 : //
1017 3 : CATCH_REQUIRE(advgetopt::validator_duration::convert_string("22.3s", 0, duration));
1018 1 : CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::nearly_equal(duration, 22.3, 0.0));
1019 :
1020 : // "seconds" is the default
1021 : //
1022 3 : CATCH_REQUIRE(advgetopt::validator_duration::convert_string("1.05", 0, duration));
1023 1 : CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::nearly_equal(duration, 1.05, 0.0));
1024 :
1025 : // number can start with a decimal point
1026 : //
1027 3 : CATCH_REQUIRE(advgetopt::validator_duration::convert_string(".0503", 0, duration));
1028 1 : CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::nearly_equal(duration, 0.0503, 0.0));
1029 : }
1030 4 : CATCH_END_SECTION()
1031 :
1032 4 : CATCH_START_SECTION("duration_validator: verify the duration validator (multiple values)")
1033 : {
1034 1 : double duration(0.0);
1035 3 : CATCH_REQUIRE(advgetopt::validator_duration::convert_string("1d 3h 2m 15.3s", 0, duration));
1036 1 : CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::nearly_equal(duration, 1.0 * 86400.0 + 3.0 * 3600.0 + 2.0 * 60.0 + 15.3, 0.0));
1037 :
1038 : // same in uppercase
1039 3 : CATCH_REQUIRE(advgetopt::validator_duration::convert_string("1D 3H 2M 15.3S", 0, duration));
1040 1 : CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::nearly_equal(duration, 1.0 * 86400.0 + 3.0 * 3600.0 + 2.0 * 60.0 + 15.3, 0.0));
1041 :
1042 3 : CATCH_REQUIRE(advgetopt::validator_duration::convert_string("3d 15h 52m 21.801s", 0, duration));
1043 1 : CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::nearly_equal(duration, 3.0 * 86400.0 + 15.0 * 3600.0 + 52.0 * 60.0 + 21.801, 0.0));
1044 : }
1045 4 : CATCH_END_SECTION()
1046 :
1047 4 : CATCH_START_SECTION("duration_validator: verify the duration validator (one value)")
1048 : {
1049 : // this test does not verify that double conversion works since we
1050 : // have a separate test for that specific validator
1051 : //
1052 4 : for(int size(0); size < 3; ++size)
1053 : {
1054 3 : advgetopt::validator_duration::flag_t flg(advgetopt::validator_duration::VALIDATOR_DURATION_DEFAULT_FLAGS);
1055 3 : advgetopt::string_list_t flags;
1056 3 : if(size == 1)
1057 : {
1058 3 : flags.push_back("small");
1059 : }
1060 2 : else if(size == 2)
1061 : {
1062 3 : flags.push_back("large");
1063 1 : flg = advgetopt::validator_duration::VALIDATOR_DURATION_LONG;
1064 : }
1065 9 : advgetopt::validator::pointer_t duration_validator(advgetopt::validator::create("duration", flags));
1066 :
1067 3 : CATCH_REQUIRE(duration_validator != nullptr);
1068 3 : CATCH_REQUIRE(duration_validator->name() == "duration");
1069 :
1070 3003 : for(int idx(0); idx < 1000; ++idx)
1071 : {
1072 : // use smaller values between 0 and 1
1073 : // (the loop is to make sure we don't end up with "123e-10"
1074 : // type of numbers... which do not work here)
1075 : //
1076 3000 : double value(0.0);
1077 : do
1078 : {
1079 3000 : value = static_cast<double>(rand()) / static_cast<double>(RAND_MAX);
1080 : }
1081 3000 : while(value < 0.0001 && snapdev::quiet_floating_point_not_equal(value, 0.0));
1082 3000 : if(rand() % 2 == 0)
1083 : {
1084 1453 : value *= -1.0;
1085 : }
1086 3000 : std::stringstream ss;
1087 3000 : ss.precision(std::numeric_limits<double>::max_digits10);
1088 3000 : ss << value;
1089 3000 : std::string const v(ss.str());
1090 :
1091 132000 : for(std::size_t i(0); i < std::size(g_duration_suffixes); ++i)
1092 : {
1093 441000 : for(int j(0); j <= 5; ++j)
1094 : {
1095 378000 : std::string duration(v);
1096 1323000 : for(int k(0); k < j; ++k)
1097 : {
1098 : // any number of spaces in between are allowed
1099 : //
1100 945000 : duration += ' ';
1101 : }
1102 378000 : duration += g_duration_suffixes[i].f_suffix;
1103 :
1104 378000 : CATCH_REQUIRE(duration_validator->validate(duration));
1105 378000 : if(value >= 0)
1106 : {
1107 194922 : CATCH_REQUIRE(duration_validator->validate('+' + duration));
1108 : }
1109 :
1110 378000 : double result(0.0);
1111 378000 : CATCH_REQUIRE(advgetopt::validator_duration::convert_string(duration, flg, result));
1112 378000 : if(g_duration_suffixes[i].f_factor < 0.0)
1113 : {
1114 : // the 'm' special case
1115 : //
1116 18000 : if(size == 2)
1117 : {
1118 : // 'large' -- 1 month
1119 : //
1120 6000 : CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::nearly_equal(result, value * (86400.0 * 30.0)));
1121 : }
1122 : else
1123 : {
1124 : // 'small' -- 1 minute
1125 : //
1126 12000 : CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::nearly_equal(result, value * 60.0));
1127 : }
1128 : }
1129 : else
1130 : {
1131 360000 : CATCH_REQUIRE(SNAP_CATCH2_NAMESPACE::nearly_equal(result, value * g_duration_suffixes[i].f_factor));
1132 : }
1133 378000 : }
1134 : }
1135 3000 : }
1136 3 : }
1137 : }
1138 4 : CATCH_END_SECTION()
1139 :
1140 4 : CATCH_START_SECTION("duration_validator: verify the duration validator (within range)")
1141 : {
1142 : struct range_t
1143 : {
1144 : typedef std::vector<range_t> vector_t;
1145 :
1146 : double f_min = 0.0;
1147 : double f_max = 0.0;
1148 : };
1149 : struct verify_t
1150 : {
1151 : typedef std::vector<verify_t> vector_t;
1152 :
1153 : double f_value = 0.0;
1154 : bool f_valid = false;
1155 : };
1156 : struct test_t
1157 : {
1158 : typedef std::vector<test_t> vector_t;
1159 :
1160 : range_t::vector_t f_ranges = range_t::vector_t();
1161 : verify_t::vector_t f_values = verify_t::vector_t();
1162 : };
1163 :
1164 1 : test_t::vector_t tests = {
1165 : {
1166 : {
1167 : { 0.0, 1.0 },
1168 : },
1169 : {
1170 : { 0.0, true },
1171 : { 0.5, true },
1172 : { 1.0, true },
1173 : { -1.0, false },
1174 : { 2.0, false },
1175 : },
1176 : },
1177 : {
1178 : {
1179 : { 1.0, 1.0 },
1180 : { 2.0, 2.0 },
1181 : { 3.0, 3.0 },
1182 : { 4.0, 4.0 },
1183 : },
1184 : {
1185 : { 0.0, false },
1186 : { 0.5, false },
1187 : { 1.0, true },
1188 : { -1.0, false },
1189 : { 2.0, true },
1190 : { 3.1, false },
1191 : { 5.0, false },
1192 : },
1193 : },
1194 : {
1195 : {
1196 : { -1.0, 1.0 },
1197 : { -52.0, -52.0 },
1198 : { 3.0, 3.0 },
1199 : },
1200 : {
1201 : { 0.0, true },
1202 : { 0.5, true },
1203 : { 1.0, true },
1204 : { -1.0, true },
1205 : { -0.5, true },
1206 : { 2.0, false },
1207 : { 3.0, true },
1208 : { -52.0, true },
1209 : { -51.0, false },
1210 : { -52.1, false },
1211 : },
1212 : },
1213 7 : };
1214 :
1215 4 : for(auto t : tests)
1216 : {
1217 : // create the set of parameters which are ranges unless the min/max
1218 : // are equal in which case we may use either syntax
1219 : //
1220 3 : advgetopt::string_list_t params;
1221 11 : for(auto p : t.f_ranges)
1222 : {
1223 8 : if(snapdev::quiet_floating_point_equal(p.f_min, p.f_max) && (rand() & 1) == 0)
1224 : {
1225 : // if equal, then enter it as a single value 50% of the time
1226 : //
1227 2 : params.push_back(std::to_string(p.f_min));
1228 : }
1229 : else
1230 : {
1231 6 : params.push_back(std::to_string(p.f_min) + "..." + std::to_string(p.f_max));
1232 : }
1233 : }
1234 :
1235 9 : advgetopt::validator::pointer_t duration_validator(advgetopt::validator::create("duration", params));
1236 3 : CATCH_REQUIRE(duration_validator != nullptr);
1237 3 : CATCH_REQUIRE(duration_validator->name() == "duration");
1238 :
1239 25 : for(auto v : t.f_values)
1240 : {
1241 22 : std::string duration(std::to_string(v.f_value));
1242 22 : CATCH_REQUIRE(duration_validator->validate(duration) == v.f_valid);
1243 22 : }
1244 3 : }
1245 1 : }
1246 4 : CATCH_END_SECTION()
1247 8 : }
1248 :
1249 :
1250 :
1251 :
1252 1 : CATCH_TEST_CASE("size_validator", "[validator][valid][validation]")
1253 : {
1254 : #pragma GCC diagnostic push
1255 : #pragma GCC diagnostic ignored "-Wpedantic"
1256 1 : CATCH_START_SECTION("size_validator: verify the size validator")
1257 : {
1258 : // this test does not verify that double conversion works since we
1259 : // have a separate test for that specific validator
1260 : //
1261 4 : for(int mode(0); mode < 3; ++mode)
1262 : {
1263 3 : advgetopt::validator_size::flag_t flg(advgetopt::validator_size::VALIDATOR_SIZE_DEFAULT_FLAGS);
1264 3 : advgetopt::string_list_t flags;
1265 3 : if(mode == 1)
1266 : {
1267 3 : flags.push_back("si");
1268 : }
1269 2 : else if(mode == 2)
1270 : {
1271 3 : flags.push_back("legacy");
1272 1 : flg = advgetopt::validator_size::VALIDATOR_SIZE_POWER_OF_TWO;
1273 : }
1274 9 : advgetopt::validator::pointer_t size_validator(advgetopt::validator::create("size", flags));
1275 :
1276 3 : CATCH_REQUIRE(size_validator != nullptr);
1277 3 : CATCH_REQUIRE(size_validator->name() == "size");
1278 :
1279 3003 : for(int idx(0); idx < 1000; ++idx)
1280 : {
1281 : // use smaller values between 0 and about 5
1282 : //
1283 3000 : double value(static_cast<double>(rand()) / static_cast<double>(RAND_MAX / 5));
1284 3000 : if(rand() % 2 == 0)
1285 : {
1286 1512 : value *= -1.0;
1287 : }
1288 3000 : std::stringstream ss;
1289 3000 : ss.precision(std::numeric_limits<double>::max_digits10);
1290 3000 : ss << value;
1291 3000 : std::string const v(ss.str());
1292 :
1293 138000 : for(std::size_t i(0); i < std::size(g_size_suffixes); ++i)
1294 : {
1295 462000 : for(int j(0); j <= 5; ++j)
1296 : {
1297 396000 : std::string size(v);
1298 1386000 : for(int k(0); k < j; ++k)
1299 : {
1300 : // any number of spaces in between are allowed
1301 : //
1302 990000 : size += ' ';
1303 : }
1304 396000 : size += g_size_suffixes[i].f_suffix;
1305 :
1306 396000 : CATCH_REQUIRE(size_validator->validate(size));
1307 396000 : if(value >= 0)
1308 : {
1309 196416 : CATCH_REQUIRE(size_validator->validate('+' + size));
1310 : }
1311 :
1312 396000 : __int128 result(0.0);
1313 396000 : CATCH_REQUIRE(advgetopt::validator_size::convert_string(size, flg, result));
1314 :
1315 396000 : long double const base(mode == 2 ? 1024.0L : g_size_suffixes[i].f_base);
1316 396000 : long double expected(1);
1317 2376000 : for(int p(0); p < g_size_suffixes[i].f_power; ++p)
1318 : {
1319 1980000 : expected *= base;
1320 : }
1321 396000 : __int128 int_expected(expected * static_cast<long double>(value));
1322 :
1323 : //std::cerr << "converted [" << size << "] to [" << result << "] wanted [" << int_expected << "]\n";
1324 396000 : CATCH_REQUIRE(result == int_expected);
1325 396000 : }
1326 : }
1327 3000 : }
1328 3 : }
1329 : }
1330 1 : CATCH_END_SECTION()
1331 : #pragma GCC diagnostic pop
1332 1 : }
1333 :
1334 :
1335 :
1336 :
1337 4 : CATCH_TEST_CASE("regex_validator", "[validator][valid][validation]")
1338 : {
1339 4 : CATCH_START_SECTION("regex_validator: verify the regex validator")
1340 : {
1341 5 : advgetopt::validator::pointer_t regex_validator(advgetopt::validator::create("regex", {".*@.*\\..*"}));
1342 :
1343 1 : CATCH_REQUIRE(regex_validator != nullptr);
1344 1 : CATCH_REQUIRE(regex_validator->name() == "regex");
1345 :
1346 3 : CATCH_REQUIRE(regex_validator->validate("@m2osw."));
1347 3 : CATCH_REQUIRE(regex_validator->validate("contact@m2osw.com"));
1348 3 : CATCH_REQUIRE(regex_validator->validate("Contact@m2osw.com"));
1349 3 : CATCH_REQUIRE(regex_validator->validate("Contact@M2OSW.com"));
1350 :
1351 3 : CATCH_REQUIRE_FALSE(regex_validator->validate("contact@m2osw:com"));
1352 3 : CATCH_REQUIRE_FALSE(regex_validator->validate("contact!m2osw.com"));
1353 1 : }
1354 4 : CATCH_END_SECTION()
1355 :
1356 4 : CATCH_START_SECTION("regex_validator: verify the regex string (case sensitive)")
1357 : {
1358 5 : advgetopt::validator::pointer_t regex_validator(advgetopt::validator::create("regex", {"/contact@.*\\..*/"}));
1359 :
1360 1 : CATCH_REQUIRE(regex_validator != nullptr);
1361 1 : CATCH_REQUIRE(regex_validator->name() == "regex");
1362 :
1363 3 : CATCH_REQUIRE_FALSE(regex_validator->validate("@m2osw."));
1364 3 : CATCH_REQUIRE(regex_validator->validate("contact@m2osw.com"));
1365 3 : CATCH_REQUIRE_FALSE(regex_validator->validate("Contact@m2osw.com"));
1366 3 : CATCH_REQUIRE_FALSE(regex_validator->validate("Contact@M2OSW.com"));
1367 :
1368 3 : CATCH_REQUIRE_FALSE(regex_validator->validate("contact@m2osw:com"));
1369 3 : CATCH_REQUIRE_FALSE(regex_validator->validate("contact!m2osw.com"));
1370 1 : }
1371 4 : CATCH_END_SECTION()
1372 :
1373 4 : CATCH_START_SECTION("regex_validator: verify the regex string (case insensitive)")
1374 : {
1375 5 : advgetopt::validator::pointer_t regex_validator(advgetopt::validator::create("regex", {"/contact@.*\\..*/i"}));
1376 :
1377 1 : CATCH_REQUIRE(regex_validator != nullptr);
1378 1 : CATCH_REQUIRE(regex_validator->name() == "regex");
1379 :
1380 3 : CATCH_REQUIRE_FALSE(regex_validator->validate("@m2osw."));
1381 3 : CATCH_REQUIRE(regex_validator->validate("contact@m2osw.com"));
1382 3 : CATCH_REQUIRE(regex_validator->validate("Contact@m2osw.com"));
1383 3 : CATCH_REQUIRE(regex_validator->validate("Contact@M2OSW.com"));
1384 :
1385 3 : CATCH_REQUIRE_FALSE(regex_validator->validate("contact@m2osw:com"));
1386 3 : CATCH_REQUIRE_FALSE(regex_validator->validate("contact!m2osw.com"));
1387 1 : }
1388 4 : CATCH_END_SECTION()
1389 :
1390 4 : CATCH_START_SECTION("regex_validator: verify direct regex string (case insensitive)")
1391 : {
1392 3 : advgetopt::validator::pointer_t regex_validator(advgetopt::validator::create("/contact@.*\\..*/i"));
1393 :
1394 1 : CATCH_REQUIRE(regex_validator != nullptr);
1395 1 : CATCH_REQUIRE(regex_validator->name() == "regex");
1396 :
1397 3 : CATCH_REQUIRE_FALSE(regex_validator->validate("@m2osw."));
1398 3 : CATCH_REQUIRE(regex_validator->validate("contact@m2osw.com"));
1399 3 : CATCH_REQUIRE(regex_validator->validate("Contact@m2osw.com"));
1400 3 : CATCH_REQUIRE(regex_validator->validate("Contact@M2OSW.com"));
1401 :
1402 3 : CATCH_REQUIRE_FALSE(regex_validator->validate("contact@m2osw:com"));
1403 3 : CATCH_REQUIRE_FALSE(regex_validator->validate("contact!m2osw.com"));
1404 1 : }
1405 4 : CATCH_END_SECTION()
1406 4 : }
1407 :
1408 :
1409 :
1410 :
1411 :
1412 :
1413 :
1414 :
1415 1 : CATCH_TEST_CASE("invalid_validator_factory", "[validator][invalid][validation]")
1416 : {
1417 1 : CATCH_START_SECTION("invalid_validator_factory: register duplicated factories")
1418 : {
1419 : class duplicate_integer
1420 : : public advgetopt::validator
1421 : {
1422 : public:
1423 0 : virtual std::string name() const override
1424 : {
1425 0 : return "integer";
1426 : }
1427 :
1428 0 : virtual bool validate(std::string const & value) const override
1429 : {
1430 0 : return value == "123";
1431 : }
1432 : };
1433 : class duplicate_factory
1434 : : public advgetopt::validator_factory
1435 : {
1436 : public:
1437 2 : virtual std::string get_name() const override
1438 : {
1439 6 : return "integer";
1440 : }
1441 :
1442 0 : virtual std::shared_ptr<advgetopt::validator> create(advgetopt::string_list_t const & data) const override
1443 : {
1444 0 : snapdev::NOT_USED(data); // ignore `data`
1445 0 : return std::make_shared<duplicate_integer>();
1446 : }
1447 : };
1448 1 : std::unique_ptr<advgetopt::validator_factory> factory(new duplicate_factory());
1449 3 : CATCH_REQUIRE_THROWS_MATCHES(
1450 : advgetopt::validator::register_validator(*factory.get())
1451 : , advgetopt::getopt_logic_error
1452 : , Catch::Matchers::ExceptionMessage(
1453 : "getopt_logic_error: you have two or more validator factories named \"integer\"."));
1454 1 : }
1455 1 : CATCH_END_SECTION()
1456 1 : }
1457 :
1458 1 : CATCH_TEST_CASE("invalid_validator_create", "[validator][invalid][validation]")
1459 : {
1460 1 : CATCH_START_SECTION("invalid_validator_create: verify missing ')' in string based create")
1461 : {
1462 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: validator(): parameter list must end with ')'. Remaining input: \"...EOS\"");
1463 3 : advgetopt::validator::pointer_t validator(advgetopt::validator::create("integer(1...7, 11...15"));
1464 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
1465 1 : CATCH_REQUIRE(validator == nullptr);
1466 :
1467 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: validator(): parameter list must end with ')'. Remaining input: \"...EOS\"");
1468 3 : validator = advgetopt::validator::create("regex([a-z]+");
1469 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
1470 1 : CATCH_REQUIRE(validator == nullptr);
1471 :
1472 3 : validator = advgetopt::validator::create(" ");
1473 1 : CATCH_REQUIRE(validator == nullptr);
1474 :
1475 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: validator(): expected a regex, an identifier or a string inside the () of a parameter. Remaining input: \"[a-z]+))\"");
1476 3 : validator = advgetopt::validator::create("regex(([a-z]+))");
1477 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
1478 1 : CATCH_REQUIRE(validator == nullptr);
1479 :
1480 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: validator(): parameters must be separated by ','. Remaining input: \"...EOS\"");
1481 3 : validator = advgetopt::validator::create("keywords(foo, blah error)");
1482 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
1483 1 : CATCH_REQUIRE(validator == nullptr);
1484 :
1485 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: validator(): unexpected token in validator definition; expected an identifier. Remaining input: \"missing, name)\".");
1486 3 : validator = advgetopt::validator::create("(missing, name)");
1487 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
1488 1 : CATCH_REQUIRE(validator == nullptr);
1489 :
1490 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: validator(): unexpected character for an identifier (10).");
1491 3 : validator = advgetopt::validator::create("keywords(missing, name)\n|\ninteger(33)");
1492 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
1493 1 : CATCH_REQUIRE(validator == nullptr);
1494 :
1495 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: validator(): validator definitions must be separated by '|'. Remaining input: \"33)\"");
1496 3 : validator = advgetopt::validator::create("keywords(missing, name) integer(33)");
1497 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
1498 1 : CATCH_REQUIRE(validator == nullptr);
1499 1 : }
1500 1 : CATCH_END_SECTION()
1501 1 : }
1502 :
1503 1 : CATCH_TEST_CASE("invalid_length_validator", "[validator][invalid][validation]")
1504 : {
1505 1 : CATCH_START_SECTION("invalid_length_validator: verify invalid length ranges")
1506 : {
1507 1 : advgetopt::string_list_t range{
1508 : "abc",
1509 : "abc...6",
1510 : "3...def",
1511 8 : "10...1"};
1512 :
1513 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: abc is not a valid standalone value for your ranges; it must only be digits, optionally preceded by a sign (+ or -) and not overflow an int64_t value.");
1514 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: abc is not a valid value for your range's start; it must only be digits, optionally preceded by a sign (+ or -) and not overflow an int64_t value.");
1515 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: def is not a valid value for your range's end; it must only be digits, optionally preceded by a sign (+ or -) and not overflow an int64_t value.");
1516 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: 10 has to be smaller or equal to 1; you have an invalid range.");
1517 :
1518 3 : advgetopt::validator::pointer_t length_validator(advgetopt::validator::create("length", range));
1519 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
1520 1 : }
1521 1 : CATCH_END_SECTION()
1522 4 : }
1523 :
1524 1 : CATCH_TEST_CASE("invalid_integer_validator", "[validator][invalid][validation]")
1525 : {
1526 1 : CATCH_START_SECTION("invalid_integer_validator: verify invalid integer ranges")
1527 : {
1528 1 : advgetopt::string_list_t range{
1529 : "abc",
1530 : "abc...6",
1531 : "3...def",
1532 8 : "10...1"};
1533 :
1534 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: abc is not a valid standalone value for your ranges; it must only be digits, optionally preceded by a sign (+ or -) and not overflow an int64_t value.");
1535 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: abc is not a valid value for your range's start; it must only be digits, optionally preceded by a sign (+ or -) and not overflow an int64_t value.");
1536 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: def is not a valid value for your range's end; it must only be digits, optionally preceded by a sign (+ or -) and not overflow an int64_t value.");
1537 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: 10 has to be smaller or equal to 1; you have an invalid range.");
1538 :
1539 3 : advgetopt::validator::pointer_t integer_validator(advgetopt::validator::create("integer", range));
1540 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
1541 1 : }
1542 1 : CATCH_END_SECTION()
1543 4 : }
1544 :
1545 1 : CATCH_TEST_CASE("invalid_double_validator", "[validator][invalid][validation]")
1546 : {
1547 1 : CATCH_START_SECTION("invalid_double_validator: verify invalid double ranges")
1548 : {
1549 1 : advgetopt::string_list_t range{
1550 : "abc",
1551 : "abc...6.3",
1552 : "13.3...def",
1553 8 : "10.5...1.2"};
1554 :
1555 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: abc is not a valid standalone value; it must be a valid floating point, optionally preceded by a sign (+ or -).");
1556 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: abc is not a valid value for your range's start; it must be a valid floating point, optionally preceded by a sign (+ or -).");
1557 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: def is not a valid value for your range's end; it must be a valid floating point, optionally preceded by a sign (+ or -).");
1558 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: 10.5 has to be smaller or equal to 1.2; you have an invalid range.");
1559 :
1560 3 : advgetopt::validator::pointer_t integer_validator(advgetopt::validator::create("double", range));
1561 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
1562 1 : }
1563 1 : CATCH_END_SECTION()
1564 4 : }
1565 :
1566 6 : CATCH_TEST_CASE("invalid_duration_validator", "[invalid][validation]")
1567 : {
1568 6 : CATCH_START_SECTION("invalid_duration_validator: verify invalid duration flags")
1569 : {
1570 1 : advgetopt::string_list_t range{
1571 : "small",
1572 : "medium",
1573 7 : "large"};
1574 :
1575 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: medium is not a valid duration or flag.");
1576 3 : advgetopt::validator::pointer_t duration_validator(advgetopt::validator::create("duration", range));
1577 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
1578 :
1579 3 : CATCH_REQUIRE_FALSE(duration_validator->validate(""));
1580 3 : CATCH_REQUIRE_FALSE(duration_validator->validate(" "));
1581 3 : CATCH_REQUIRE_FALSE(duration_validator->validate("+"));
1582 3 : CATCH_REQUIRE_FALSE(duration_validator->validate("-"));
1583 3 : CATCH_REQUIRE_FALSE(duration_validator->validate("alpha"));
1584 3 : CATCH_REQUIRE_FALSE(duration_validator->validate("3.5 beta"));
1585 3 : CATCH_REQUIRE_FALSE(duration_validator->validate("7.5delta"));
1586 3 : CATCH_REQUIRE_FALSE(duration_validator->validate("+8.1 gamma"));
1587 3 : CATCH_REQUIRE_FALSE(duration_validator->validate("-2.3eta"));
1588 3 : CATCH_REQUIRE_FALSE(duration_validator->validate("-202.3 HERO"));
1589 3 : CATCH_REQUIRE_FALSE(duration_validator->validate("-7.31Hr"));
1590 3 : CATCH_REQUIRE_FALSE(duration_validator->validate("-1.32mom"));
1591 3 : CATCH_REQUIRE_FALSE(duration_validator->validate("-5.36 secs"));
1592 3 : CATCH_REQUIRE_FALSE(duration_validator->validate("28.901 wkS"));
1593 3 : CATCH_REQUIRE_FALSE(duration_validator->validate("28 YY"));
1594 3 : CATCH_REQUIRE_FALSE(duration_validator->validate("2..8 year"));
1595 1 : }
1596 6 : CATCH_END_SECTION()
1597 :
1598 6 : CATCH_START_SECTION("invalid_duration_validator: verify invalid duration (text)")
1599 : {
1600 5 : advgetopt::string_list_t range{"alpha"};
1601 :
1602 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: alpha is not a valid duration or flag.");
1603 3 : advgetopt::validator::pointer_t duration_validator(advgetopt::validator::create("duration", range));
1604 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
1605 :
1606 3 : CATCH_REQUIRE_FALSE(duration_validator->validate("2..8 year"));
1607 1 : }
1608 6 : CATCH_END_SECTION()
1609 :
1610 6 : CATCH_START_SECTION("invalid_duration_validator: verify invalid duration (two periods)")
1611 : {
1612 5 : advgetopt::string_list_t range{"3..91"};
1613 :
1614 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: 3..91 is not a valid duration or flag.");
1615 3 : advgetopt::validator::pointer_t duration_validator(advgetopt::validator::create("duration", range));
1616 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
1617 :
1618 3 : CATCH_REQUIRE_FALSE(duration_validator->validate("year"));
1619 1 : }
1620 6 : CATCH_END_SECTION()
1621 :
1622 6 : CATCH_START_SECTION("invalid_duration_validator: verify invalid duration (bad start)")
1623 : {
1624 5 : advgetopt::string_list_t range{"D...9.1"};
1625 :
1626 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: D is not a valid value for your range's start; it must be a valid duration, optionally preceded by a sign (+ or -).");
1627 3 : advgetopt::validator::pointer_t duration_validator(advgetopt::validator::create("duration", range));
1628 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
1629 :
1630 3 : CATCH_REQUIRE_FALSE(duration_validator->validate("days"));
1631 1 : }
1632 6 : CATCH_END_SECTION()
1633 :
1634 6 : CATCH_START_SECTION("invalid_duration_validator: verify invalid duration (bad end)")
1635 : {
1636 5 : advgetopt::string_list_t range{"3.1...E"};
1637 :
1638 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: E is not a valid value for your range's end; it must be a valid duration, optionally preceded by a sign (+ or -).");
1639 3 : advgetopt::validator::pointer_t duration_validator(advgetopt::validator::create("duration", range));
1640 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
1641 :
1642 3 : CATCH_REQUIRE_FALSE(duration_validator->validate("days"));
1643 1 : }
1644 6 : CATCH_END_SECTION()
1645 :
1646 6 : CATCH_START_SECTION("invalid_duration_validator: verify invalid duration (start > end)")
1647 : {
1648 5 : advgetopt::string_list_t range{"3.1...2.9"};
1649 :
1650 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: 3.1 has to be smaller or equal to 2.9; you have an invalid duration range.");
1651 3 : advgetopt::validator::pointer_t duration_validator(advgetopt::validator::create("duration", range));
1652 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
1653 :
1654 3 : CATCH_REQUIRE_FALSE(duration_validator->validate("days"));
1655 1 : }
1656 6 : CATCH_END_SECTION()
1657 24 : }
1658 :
1659 :
1660 :
1661 1 : CATCH_TEST_CASE("invalid_email_validator", "[invalid][validation]")
1662 : {
1663 1 : CATCH_START_SECTION("invalid_email_validator: verify emails with invalid parameters.")
1664 : {
1665 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: validator_email() supports zero or one parameter.");
1666 3 : advgetopt::validator::pointer_t keywords(advgetopt::validator::create("email(single, multiple)"));
1667 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
1668 1 : CATCH_REQUIRE(keywords != nullptr);
1669 :
1670 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: validator_email(): unknown parameter \"orange\".");
1671 3 : keywords = advgetopt::validator::create("email(orange)");
1672 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
1673 1 : CATCH_REQUIRE(keywords != nullptr);
1674 1 : }
1675 1 : CATCH_END_SECTION()
1676 1 : }
1677 :
1678 :
1679 :
1680 1 : CATCH_TEST_CASE("invalid_keywords_validator", "[invalid][validation]")
1681 : {
1682 1 : CATCH_START_SECTION("invalid_keywords_validator: verify that keywords without parameters fail.")
1683 : {
1684 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: validator_keywords() requires at least one parameter.");
1685 3 : advgetopt::validator::pointer_t keywords(advgetopt::validator::create("keywords"));
1686 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
1687 1 : CATCH_REQUIRE(keywords != nullptr);
1688 :
1689 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: validator_keywords() requires at least one parameter.");
1690 3 : keywords = advgetopt::validator::create("keywords()");
1691 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
1692 1 : CATCH_REQUIRE(keywords != nullptr);
1693 1 : }
1694 1 : CATCH_END_SECTION()
1695 1 : }
1696 :
1697 :
1698 :
1699 1 : CATCH_TEST_CASE("invalid_list_validator", "[invalid][validation]")
1700 : {
1701 1 : CATCH_START_SECTION("invalid_list_validator: verify that list validators do not accept parameters.")
1702 : {
1703 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: validator_list() does not support any parameter.");
1704 3 : advgetopt::validator::pointer_t list(advgetopt::validator::create("list(with, parameters)"));
1705 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
1706 1 : CATCH_REQUIRE(list != nullptr);
1707 1 : }
1708 1 : CATCH_END_SECTION()
1709 1 : }
1710 :
1711 :
1712 :
1713 1 : CATCH_TEST_CASE("invalid_size_validator", "[invalid][validation]")
1714 : {
1715 1 : CATCH_START_SECTION("invalid_size_validator: verify invalid duration flags")
1716 : {
1717 1 : advgetopt::string_list_t flags{
1718 : "si",
1719 : "future",
1720 7 : "legacy"};
1721 :
1722 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: future is not a valid flag for the size validator.");
1723 3 : advgetopt::validator::pointer_t size_validator(advgetopt::validator::create("size", flags));
1724 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
1725 :
1726 3 : CATCH_REQUIRE_FALSE(size_validator->validate(""));
1727 3 : CATCH_REQUIRE_FALSE(size_validator->validate(" "));
1728 3 : CATCH_REQUIRE_FALSE(size_validator->validate("+"));
1729 3 : CATCH_REQUIRE_FALSE(size_validator->validate("-"));
1730 3 : CATCH_REQUIRE_FALSE(size_validator->validate("size"));
1731 3 : CATCH_REQUIRE_FALSE(size_validator->validate("3.5 large"));
1732 3 : CATCH_REQUIRE_FALSE(size_validator->validate("-1.31body"));
1733 3 : CATCH_REQUIRE_FALSE(size_validator->validate("7.5small"));
1734 3 : CATCH_REQUIRE_FALSE(size_validator->validate("+8.1 tiny"));
1735 3 : CATCH_REQUIRE_FALSE(size_validator->validate("-2.3medium"));
1736 3 : CATCH_REQUIRE_FALSE(size_validator->validate("1000kbit"));
1737 3 : CATCH_REQUIRE_FALSE(size_validator->validate("7 monster"));
1738 3 : CATCH_REQUIRE_FALSE(size_validator->validate("-101.101egret"));
1739 3 : CATCH_REQUIRE_FALSE(size_validator->validate("11 products"));
1740 3 : CATCH_REQUIRE_FALSE(size_validator->validate("1.01 tractor"));
1741 3 : CATCH_REQUIRE_FALSE(size_validator->validate("+7.0 years"));
1742 3 : CATCH_REQUIRE_FALSE(size_validator->validate("-51.7zeroes"));
1743 3 : CATCH_REQUIRE_FALSE(size_validator->validate("+121gruffalos"));
1744 3 : CATCH_REQUIRE_FALSE(size_validator->validate("++1.7 KiB"));
1745 3 : CATCH_REQUIRE_FALSE(size_validator->validate("-+3.1 MiB"));
1746 3 : CATCH_REQUIRE_FALSE(size_validator->validate("+-9.2 GiB"));
1747 3 : CATCH_REQUIRE_FALSE(size_validator->validate("--19.4 PiB"));
1748 3 : CATCH_REQUIRE_FALSE(size_validator->validate("-3.5.4B"));
1749 1 : }
1750 1 : CATCH_END_SECTION()
1751 4 : }
1752 :
1753 6 : CATCH_TEST_CASE("invalid_regex_validator", "[validator][invalid][validation]")
1754 : {
1755 6 : CATCH_START_SECTION("invalid_regex_validator: verify invalid regex flags")
1756 : {
1757 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag f in regular expression \"/contact@.*\\..*/f\".");
1758 5 : advgetopt::validator::pointer_t regex_validator(advgetopt::validator::create("regex", {"/contact@.*\\..*/f"}));
1759 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
1760 :
1761 1 : CATCH_REQUIRE(regex_validator != nullptr);
1762 1 : CATCH_REQUIRE(regex_validator->name() == "regex");
1763 :
1764 3 : CATCH_REQUIRE_FALSE(regex_validator->validate("@m2osw."));
1765 3 : CATCH_REQUIRE(regex_validator->validate("contact@m2osw.com"));
1766 3 : CATCH_REQUIRE_FALSE(regex_validator->validate("Contact@m2osw.com"));
1767 3 : CATCH_REQUIRE_FALSE(regex_validator->validate("Contact@M2OSW.com"));
1768 :
1769 3 : CATCH_REQUIRE_FALSE(regex_validator->validate("contact@m2osw:com"));
1770 3 : CATCH_REQUIRE_FALSE(regex_validator->validate("contact!m2osw.com"));
1771 1 : }
1772 6 : CATCH_END_SECTION()
1773 :
1774 6 : CATCH_START_SECTION("invalid_regex_validator: verify invalid regex character")
1775 : {
1776 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: validator(): unexpected character for a regular expression (10).");
1777 3 : advgetopt::validator::pointer_t regex_validator(advgetopt::validator::create("regex(/contact@.*\n..*/)"));
1778 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
1779 1 : CATCH_REQUIRE(regex_validator == nullptr);
1780 :
1781 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: validator(): unexpected escaped character for a regular expression (13).");
1782 3 : regex_validator = advgetopt::validator::create("regex(/contact@.*\\\r..*/)");
1783 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
1784 1 : CATCH_REQUIRE(regex_validator == nullptr);
1785 :
1786 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: validator(): unexpected flag character for a regular expression (57).");
1787 3 : regex_validator = advgetopt::validator::create("regex(/contact@.*..*/91)");
1788 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
1789 1 : CATCH_REQUIRE(regex_validator == nullptr);
1790 :
1791 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: validator(): unexpected character for an identifier (10).");
1792 3 : regex_validator = advgetopt::validator::create("regex(not\nexpected)");
1793 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
1794 1 : CATCH_REQUIRE(regex_validator == nullptr);
1795 1 : }
1796 6 : CATCH_END_SECTION()
1797 :
1798 6 : CATCH_START_SECTION("invalid_regex_validator: verify invalid regex: missing ending /")
1799 : {
1800 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag * in regular expression \"/contact@.*\\..*\".");
1801 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag . in regular expression \"/contact@.*\\..*\".");
1802 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag . in regular expression \"/contact@.*\\..*\".");
1803 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag \\ in regular expression \"/contact@.*\\..*\".");
1804 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag * in regular expression \"/contact@.*\\..*\".");
1805 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag . in regular expression \"/contact@.*\\..*\".");
1806 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag @ in regular expression \"/contact@.*\\..*\".");
1807 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag t in regular expression \"/contact@.*\\..*\".");
1808 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag c in regular expression \"/contact@.*\\..*\".");
1809 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag a in regular expression \"/contact@.*\\..*\".");
1810 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag t in regular expression \"/contact@.*\\..*\".");
1811 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag n in regular expression \"/contact@.*\\..*\".");
1812 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag o in regular expression \"/contact@.*\\..*\".");
1813 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: unsupported regex flag c in regular expression \"/contact@.*\\..*\".");
1814 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: invalid regex definition, ending / is missing in \"/contact@.*\\..*\".");
1815 :
1816 5 : advgetopt::validator::pointer_t regex_validator(advgetopt::validator::create("regex", {"/contact@.*\\..*"}));
1817 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
1818 :
1819 1 : CATCH_REQUIRE(regex_validator != nullptr);
1820 1 : CATCH_REQUIRE(regex_validator->name() == "regex");
1821 :
1822 3 : CATCH_REQUIRE_FALSE(regex_validator->validate("@m2osw."));
1823 3 : CATCH_REQUIRE(regex_validator->validate("contact@m2osw.com"));
1824 3 : CATCH_REQUIRE_FALSE(regex_validator->validate("Contact@m2osw.com"));
1825 3 : CATCH_REQUIRE_FALSE(regex_validator->validate("Contact@M2OSW.com"));
1826 :
1827 3 : CATCH_REQUIRE_FALSE(regex_validator->validate("contact@m2osw:com"));
1828 3 : CATCH_REQUIRE_FALSE(regex_validator->validate("contact!m2osw.com"));
1829 1 : }
1830 6 : CATCH_END_SECTION()
1831 :
1832 6 : CATCH_START_SECTION("invalid_regex_validator: verify regex refuses more than one parameter")
1833 : {
1834 3 : SNAP_CATCH2_NAMESPACE::push_expected_log(
1835 : "error: validator_regex() only supports one parameter;"
1836 : " 2 were supplied;"
1837 : " single or double quotation may be required?");
1838 5 : advgetopt::validator::create("regex", {"[a-z]+", "[0-9]+"});
1839 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
1840 :
1841 3 : SNAP_CATCH2_NAMESPACE::push_expected_log(
1842 : "error: validator_regex() only supports one parameter;"
1843 : " 2 were supplied;"
1844 : " single or double quotation may be required?");
1845 3 : advgetopt::validator::create("regex([a-z]+, [0-9]+)");
1846 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
1847 :
1848 3 : SNAP_CATCH2_NAMESPACE::push_expected_log(
1849 : "error: validator_regex() only supports one parameter;"
1850 : " 3 were supplied;"
1851 : " single or double quotation may be required?");
1852 5 : advgetopt::validator::create("regex", {"[a-z]+", "[0-9]+", "[#!@]"});
1853 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
1854 :
1855 3 : SNAP_CATCH2_NAMESPACE::push_expected_log(
1856 : "error: validator_regex() only supports one parameter;"
1857 : " 3 were supplied;"
1858 : " single or double quotation may be required?");
1859 3 : advgetopt::validator::create("regex(\"[a-z]+\", \"[0-9]+\", \"[#!@]\")");
1860 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
1861 : }
1862 6 : CATCH_END_SECTION()
1863 :
1864 6 : CATCH_START_SECTION("invalid_regex_validator: verify two regex params")
1865 : {
1866 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: validator_regex() only supports one parameter; 2 were supplied; single or double quotation may be required?");
1867 3 : advgetopt::validator::pointer_t regex_validator(advgetopt::validator::create("regex(/one/a, /two/b)"));
1868 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
1869 :
1870 1 : CATCH_REQUIRE(regex_validator != nullptr);
1871 1 : CATCH_REQUIRE(regex_validator->name() == "regex");
1872 :
1873 3 : CATCH_REQUIRE_FALSE(regex_validator->validate("@m2osw."));
1874 3 : CATCH_REQUIRE_FALSE(regex_validator->validate("contact@m2osw.com"));
1875 3 : CATCH_REQUIRE_FALSE(regex_validator->validate("Contact@m2osw.com"));
1876 3 : CATCH_REQUIRE_FALSE(regex_validator->validate("Contact@M2OSW.com"));
1877 :
1878 3 : CATCH_REQUIRE_FALSE(regex_validator->validate("contact@m2osw:com"));
1879 3 : CATCH_REQUIRE_FALSE(regex_validator->validate("contact!m2osw.com"));
1880 1 : }
1881 6 : CATCH_END_SECTION()
1882 :
1883 6 : CATCH_START_SECTION("invalid_regex_validator: verify two regex params")
1884 : {
1885 3 : SNAP_CATCH2_NAMESPACE::push_expected_log("error: validator(): unexpected character for an identifier (10).");
1886 3 : advgetopt::validator::pointer_t regex_validator(advgetopt::validator::create("regex('/one/'\n,'/two/b')"));
1887 1 : SNAP_CATCH2_NAMESPACE::expected_logs_stack_is_empty();
1888 1 : CATCH_REQUIRE(regex_validator == nullptr);
1889 1 : }
1890 6 : CATCH_END_SECTION()
1891 :
1892 6 : }
1893 :
1894 :
1895 : // vim: ts=4 sw=4 et
|