]> git.ipfire.org Git - thirdparty/snort3.git/blame - src/framework/parameter.cc
Pull request #4267: framework: add workaround to support case from double to unsigned
[thirdparty/snort3.git] / src / framework / parameter.cc
CommitLineData
38939e49 1//--------------------------------------------------------------------------
b88d016d 2// Copyright (C) 2014-2024 Cisco and/or its affiliates. All rights reserved.
38939e49
RC
3//
4// This program is free software; you can redistribute it and/or modify it
5// under the terms of the GNU General Public License Version 2 as published
6// by the Free Software Foundation. You may not use, modify or distribute
7// this program under any other version of the GNU General Public License.
8//
9// This program is distributed in the hope that it will be useful, but
10// WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12// General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License along
15// with this program; if not, write to the Free Software Foundation, Inc.,
16// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17//--------------------------------------------------------------------------
75a57075
RC
18// parameter.cc author Russ Combs <rucombs@cisco.com>
19
02d63397
MA
20#ifdef HAVE_CONFIG_H
21#include "config.h"
22#endif
23
fc915f61 24#include "parameter.h"
75a57075 25
02d63397 26#include <cassert>
75a57075 27
75a57075
RC
28#include <iomanip>
29#include <sstream>
a478eca7 30#include <type_traits>
75a57075 31#include <vector>
75a57075 32
fc915f61
RC
33#include "utils/dnet_header.h"
34
02d63397
MA
35#include "value.h"
36
a19c078d 37using namespace snort;
fe2d9c00
RC
38using namespace std;
39
020356df
RC
40//--------------------------------------------------------------------------
41// helpers
42//--------------------------------------------------------------------------
43
44static bool is_sep(char c)
45{ return !c || c == '|' || isspace(c); }
46
47static const char* find(const char* r, const char* s)
48{
49 size_t n = strlen(s);
50
51 if ( !n )
52 return nullptr;
53
54 const char* t = strstr(r, s);
55
56 while ( t )
57 {
58 if ( (t == r || is_sep(t[-1])) && is_sep(t[n]) )
59 return t;
60
61 t = strstr(t+n, s);
62 }
63 return nullptr;
64}
65
66static unsigned get_index(const char* r, const char* t)
67{
68 unsigned idx = 0;
69 const char* p = strchr(r, '|');
70
71 while ( p && p < t )
72 {
73 ++idx;
74 p = strchr(p+1, '|');
75 }
76 return idx;
77}
78
3b8d4148 79static size_t split(const string& s, vector<string>& strs)
020356df 80{
3b8d4148 81 stringstream ss(s);
82 string tok;
020356df 83
3b8d4148 84 while ( ss >> tok )
85 strs.push_back(tok);
020356df
RC
86
87 return strs.size();
88}
89
a478eca7
OSSIC
90template <bool RV, typename T>
91static bool str2num(const char* r, T& t)
020356df 92{
a478eca7 93 const int n = 5;
020356df 94
a478eca7
OSSIC
95 if ( *r != 'm' )
96 return false;
020356df 97
a478eca7
OSSIC
98 if ( !strncmp(r, "maxSZ", n) )
99 r = (sizeof(size_t) == 4) ? "max32" : "max53";
020356df 100
a478eca7 101 bool res = true;
9d1d5865 102
a478eca7
OSSIC
103 if ( !strncmp(r, "max31", n) )
104 t = 2147483647;
9d1d5865 105
a478eca7
OSSIC
106 else if ( !strncmp(r, "max32", n) )
107 t = 4294967295;
108
109 // Lua represents numbers in a 64-bit double. The max representable value is 9007199254740992
110 // and the min is -9007199254740992
111 else if ( !strncmp(r, "max53", n) )
112 t = 9007199254740992;
113
114 else if ( !strncmp(r, "max63", n) )
115 t = 9223372036854775807;
116
117 else if ( !strncmp(r, "max64", n) )
118 t = std::is_same_v<T, int64_t> ? -1 : 18446744073709551615ULL;
119
120 else
121 res = false;
122
123 return res and (r[n] == '\0' or (RV and r[n] == ':'));
124}
125
126int64_t Parameter::get_int(const char* r)
127{
49af2b2c
RC
128 char* end = nullptr;
129 int64_t i = (int64_t)strtoll(r, &end, 0);
a478eca7
OSSIC
130
131 if (!str2num<true>(r, i))
132 assert(!*end or *end == ':');
49af2b2c
RC
133
134 return i;
020356df
RC
135}
136
9d1d5865
RD
137uint64_t Parameter::get_uint(const char* r)
138{
a478eca7
OSSIC
139 char* end = nullptr;
140 uint64_t i = (uint64_t)strtoull(r, &end, 0);
9d1d5865 141
a478eca7
OSSIC
142 if (!str2num<true>(r, i))
143 assert(!*end or *end == ':');
9d1d5865 144
a478eca7
OSSIC
145 return i;
146}
9d1d5865 147
a478eca7
OSSIC
148int64_t Parameter::get_int(const char* r, bool& is_correct)
149{
150 char* end = nullptr;
151 int64_t i = (int64_t)strtoll(r, &end, 0);
9d1d5865 152
a478eca7 153 is_correct = str2num<false>(r, i) or !*end;
9d1d5865 154
a478eca7
OSSIC
155 return i;
156}
157
158uint64_t Parameter::get_uint(const char* r, bool& is_correct)
159{
9d1d5865
RD
160 char* end = nullptr;
161 uint64_t i = (uint64_t)strtoull(r, &end, 0);
a478eca7
OSSIC
162
163 is_correct = str2num<false>(r, i) or !*end;
9d1d5865
RD
164
165 return i;
166}
167
020356df
RC
168//--------------------------------------------------------------------------
169// validation methods
170//--------------------------------------------------------------------------
171
98a4cad5 172static bool valid_bool(const Value& v, const char*)
75a57075
RC
173{
174 return v.get_type() == Value::VT_BOOL;
175}
176
32edb5f8 177// FIXIT-L allow multiple , separated ranges
9d1d5865 178static bool valid_int(Value& v, const char* r)
75a57075 179{
9d1d5865 180 bool signed_values;
a478eca7
OSSIC
181 bool is_correct = true;
182 uint64_t num;
183
9d1d5865
RD
184 switch (v.get_type())
185 {
a478eca7
OSSIC
186 case Value::VT_STR:
187 {
188 const char* str = v.get_string();
189 const char f = str[0];
190
191 if (f == '\0' or isspace(f))
9d1d5865 192 return false;
a478eca7
OSSIC
193
194 signed_values = ('-' == f);
195 num = signed_values ? Parameter::get_int(str, is_correct) : Parameter::get_uint(str, is_correct);
196 break;
9d1d5865 197 }
75a57075 198
a478eca7
OSSIC
199 case Value::VT_REAL:
200 {
201 double d = v.get_real();
202 signed_values = (0.0 > d);
cf03e7d9 203 num = (uint64_t)(int64_t)d;
a478eca7
OSSIC
204 break;
205 }
206
207 default:
208 return false;
209 }
210
211 if (is_correct)
212 signed_values ? v.set((int64_t)num) : v.set((uint64_t)num);
213 else
214 return false;
215
216 if (!r || !r[0])
217 return true;
218
75a57075
RC
219 // require no leading or trailing whitespace
220 // and either # | #: | :# | #:#
221 // where # is a valid pos or neg dec, hex, or octal number
222
020356df 223 const char* t = strchr(r, ':');
9d1d5865 224 if (!signed_values)
75a57075 225 {
9d1d5865
RD
226 if ('-' == r[0])
227 signed_values = true;
228 if (t && '-' == t[1])
229 signed_values = true;
020356df 230 }
75a57075 231
9d1d5865 232 if (signed_values)
75a57075 233 {
a478eca7
OSSIC
234 int64_t d = (int64_t)num;
235
9d1d5865
RD
236 if (':' != *r)
237 {
238 int64_t low = Parameter::get_int(r);
239 if (d < low)
240 return false;
241 if (!t)
242 return d == low;
243 }
244 if (t && *++t)
245 {
246 int64_t hi = Parameter::get_int(t);
247 if (d > hi)
248 return false;
249 }
250 }
251 else
252 {
a478eca7
OSSIC
253 uint64_t d = (uint64_t)num;
254
9d1d5865
RD
255 if (':' != *r)
256 {
257 uint64_t low = Parameter::get_uint(r);
258 if (d < low)
259 return false;
260 if (!t)
261 return d == low;
262 }
263 if (t && *++t)
264 {
265 uint64_t hi = Parameter::get_uint(t);
266 if (d > hi)
267 return false;
268 }
75a57075 269 }
a478eca7 270
75a57075
RC
271 return true;
272}
273
d4ff2e2c
RC
274// interval is a special case because we support a<>b and a<=>b for convenience.
275// if not for that, then dsize:1<>10; would be dsize:>1, <10; (2 parameters) but
276// that is the same as dsize:>1; dsize:<10; which is arguably easier to read and
277// not significantly worse performance and which we also, obviously, already
278// support. and note that <> and <=> are non-standard Snort-isms. so, we wind
279// up with a multivalued parameter which is best handled as a string. validation
280// must be done by the user. the advantage of using an interval instead of string
281// is that we can document the type in one place and the parameters can focus on
282// their actual, specific semantics instead of trying to explain the syntax. this
283// also ensures that an int-type range is not applied to a string.
284
98a4cad5 285static bool valid_interval(const Value&, const char*)
d4ff2e2c
RC
286{ return true; }
287
32edb5f8 288// FIXIT-L allow multiple , separated ranges
9d1d5865 289static bool valid_real(Value& v, const char* r)
75a57075 290{
9d1d5865
RD
291 if (Value::VT_STR == v.get_type())
292 {
293 const char* str = v.get_string();
294 if (!str[0])
295 return false;
296
297 double d = strtod(str, nullptr);
298 v.set(d);
299 }
300 else if (Value::VT_REAL != v.get_type())
cd53d4b7
RC
301 return false;
302
75a57075
RC
303 if ( !r )
304 return true;
305
306 double d = v.get_real();
307
308 // require no leading or trailing whitespace
309 // and either # | #: | :# | #:#
310 // where # is a valid pos or neg dec, hex, or octal number
311
020356df
RC
312 const char* t = strchr(r, ':');
313
75a57075
RC
314 if ( *r != ':' )
315 {
316 double low = strtod(r, nullptr);
317
318 if ( d < low )
319 return false;
75a57075 320
020356df
RC
321 if ( !t )
322 return d == low;
323 }
75a57075
RC
324
325 if ( t && *++t )
326 {
327 double hi = strtod(t, nullptr);
328
329 if ( d > hi )
330 return false;
331 }
332 return true;
333}
334
98a4cad5 335static bool valid_string(const Value& v, const char* r)
75a57075 336{
cd53d4b7
RC
337 if ( v.get_type() != Value::VT_STR )
338 return false;
339
7af7b4bc
RC
340 if ( r && !strcmp(r, "(optional)") )
341 return true;
342
020356df 343 size_t len = strlen(v.get_string());
75a57075
RC
344
345 if ( !r )
346 return len > 0;
347
020356df 348 size_t max = strtoul(r, nullptr, 0);
75a57075
RC
349 return len <= max;
350}
351
98a4cad5 352static bool valid_select(const Value& v, const char* r)
75a57075 353{
cd53d4b7
RC
354 if ( v.get_type() != Value::VT_STR )
355 return false;
356
75a57075
RC
357 if ( !r )
358 return false;
359
360 const char* s = v.get_string();
ba277c02 361 const char* t = find(r, s);
75a57075
RC
362
363 if ( !t )
364 return false;
365
366 return true;
367}
368
75a57075
RC
369static bool valid_enum(Value& v, const char* r)
370{
cd53d4b7
RC
371 if ( v.get_type() != Value::VT_STR )
372 return false;
373
75a57075
RC
374 if ( !r )
375 return false;
376
377 const char* s = v.get_string();
ba277c02 378 const char* t = find(r, s);
75a57075
RC
379
380 if ( !t )
381 return false;
382
383 unsigned idx = get_index(r, t);
384
d90f9feb 385 v.set_enum(idx);
75a57075
RC
386 return true;
387}
388
75a57075
RC
389static bool valid_multi(Value& v, const char* r)
390{
cd53d4b7
RC
391 if ( v.get_type() != Value::VT_STR )
392 return false;
393
75a57075
RC
394 if ( !r )
395 return false;
396
3b8d4148 397 const string str = v.get_string();
75a57075 398 vector<string> list;
3b8d4148 399 split(str, list);
75a57075 400
020356df 401 uint64_t mask = 0;
75a57075 402
d4a79f9a 403 for ( const auto& p : list )
75a57075 404 {
ba277c02 405 const char* t = find(r, p.c_str());
75a57075
RC
406 if ( !t )
407 return false;
408
020356df 409 uint64_t idx = get_index(r, t);
75a57075
RC
410
411 if ( idx < Value::mask_bits )
5f341c40 412 mask |= (1ULL << idx);
75a57075
RC
413 }
414 v.set_aux(mask);
415 return true;
416}
417
418static bool valid_mac(Value& v, const char*)
419{
cd53d4b7
RC
420 if ( v.get_type() != Value::VT_STR )
421 return false;
422
75a57075
RC
423 struct addr a;
424
425 if ( addr_pton(v.get_string(), &a) )
426 return false;
427
428 if ( a.addr_type == ADDR_TYPE_ETH )
429 v.set(a.addr_data8, 6);
430
431 else
432 return false;
433
434 return true;
435}
436
437static bool valid_ip4(Value& v, const char*)
438{
cd53d4b7
RC
439 if ( v.get_type() != Value::VT_STR )
440 return false;
441
75a57075
RC
442 uint32_t ip4 = inet_addr(v.get_string());
443
444 if ( ip4 == INADDR_NONE )
445 return false;
446
9d1d5865 447 v.set((uint64_t)ip4);
75a57075
RC
448 return true;
449}
450
451static bool valid_addr(Value& v, const char*)
452{
cd53d4b7
RC
453 if ( v.get_type() != Value::VT_STR )
454 return false;
455
75a57075
RC
456 struct addr a;
457
458 if ( addr_pton(v.get_string(), &a) )
459 return false;
466cadab 460
75a57075
RC
461 if ( a.addr_type == ADDR_TYPE_IP )
462 v.set(a.addr_data8, 4);
463
464 else if ( a.addr_type == ADDR_TYPE_IP6 )
465 v.set(a.addr_data8, 16);
466
467 else
468 return false;
469
470 return true;
471}
472
473static bool valid_bit_list(Value& v, const char* r)
474{
cd53d4b7
RC
475 if ( v.get_type() != Value::VT_STR )
476 return false;
477
75a57075 478 string pl = v.get_string();
4f14885c 479 string bs;
75a57075 480
020356df 481 size_t max = r ? strtoul(r, nullptr, 0) : 0;
75a57075
RC
482 assert(max > 0);
483
4f14885c
RC
484 if ( pl == "any" )
485 {
486 bs.assign(max+1, '1');
487 v.set(bs.c_str());
488 return true;
489 }
490 stringstream ss(pl);
491 ss >> setbase(0);
75a57075 492
4f14885c 493 bs.assign(max+1, '0');
75a57075
RC
494 int bit;
495
496 while ( ss >> bit )
497 {
020356df 498 if ( bit < 0 || (size_t)bit > max )
75a57075
RC
499 return false;
500
501 bs[bit] = '1';
502 }
503 if ( !ss.eof() )
504 return false;
505
506 v.set(bs.c_str());
507 return true;
508}
509
c06c8d5e 510static bool valid_int_list(Value& v, const char* r)
511{
512 if ( v.get_type() != Value::VT_STR )
513 return false;
514
515 string pl = v.get_string();
516
517 size_t max = r ? strtoul(r, nullptr, 0) : 0;
518 assert(max < ULONG_MAX);
519
520 stringstream ss(pl);
521 ss >> setbase(0);
522
523 int val;
524
525 while ( ss >> val )
526 {
527 if ( val < 0 || (r and (size_t)val > max) )
528 return false;
529 }
530 if ( !ss.eof() )
531 return false;
532
533 return true;
534}
535
020356df
RC
536//--------------------------------------------------------------------------
537// Parameter methods
538//--------------------------------------------------------------------------
539
75a57075
RC
540bool Parameter::validate(Value& v) const
541{
542 switch ( type )
543 {
544 // bool values
545 case PT_BOOL:
98ef91c6 546 return valid_bool(v, (const char*)range);
75a57075
RC
547
548 // num values
549 case PT_PORT:
550 if ( !range )
551 return valid_int(v, "0:65535");
d78bacf8 552 // fall through
75a57075 553 case PT_INT:
98ef91c6 554 return valid_int(v, (const char*)range);
d4ff2e2c
RC
555 case PT_INTERVAL:
556 return valid_interval(v, (const char*)range);
75a57075 557 case PT_REAL:
98ef91c6 558 return valid_real(v, (const char*)range);
75a57075
RC
559
560 // string values
561 case PT_STRING:
98ef91c6 562 return valid_string(v, (const char*)range);
75a57075 563 case PT_SELECT:
98ef91c6 564 return valid_select(v, (const char*)range);
75a57075 565 case PT_MULTI:
98ef91c6 566 return valid_multi(v, (const char*)range);
75a57075 567 case PT_ENUM:
98ef91c6 568 return valid_enum(v, (const char*)range);
7db3d57c 569 case PT_DYNAMIC:
d4a79f9a 570 return valid_select(v, (*((const RangeQuery*)range))());
75a57075
RC
571
572 // address values
573 case PT_MAC:
98ef91c6 574 return valid_mac(v, (const char*)range);
75a57075 575 case PT_IP4:
98ef91c6 576 return valid_ip4(v, (const char*)range);
75a57075 577 case PT_ADDR:
98ef91c6 578 return valid_addr(v, (const char*)range);
75a57075
RC
579
580 // list values
581 case PT_BIT_LIST:
98ef91c6 582 return valid_bit_list(v, (const char*)range);
75a57075 583
c06c8d5e 584 case PT_INT_LIST:
585 return valid_int_list(v, (const char*)range);
586
75a57075 587 case PT_ADDR_LIST:
c06c8d5e 588 // validated by user on sfip_from_string
589 // fall through
590
74957388 591 case PT_IMPLIED:
75a57075
RC
592 return true;
593
594 default:
595 break;
596 }
597 return false;
598}
599
1950cbb0 600static const char* const pt2str[Parameter::PT_MAX] =
75a57075 601{
7db3d57c 602 "table", "list", "dynamic",
d4ff2e2c 603 "bool", "int", "interval", "real", "port",
75a57075
RC
604 "string", "select", "multi", "enum",
605 "mac", "ip4", "addr",
c06c8d5e 606 "bit_list", "int_list", "addr_list", "implied"
75a57075
RC
607};
608
609const char* Parameter::get_type() const
610{
611 assert(type < Parameter::PT_MAX);
612 return pt2str[type];
613}
614
7db3d57c
RC
615const char* Parameter::get_range() const
616{
617 switch ( type )
618 {
619 case PT_TABLE:
620 case PT_LIST:
621 return nullptr;
622
623 case PT_DYNAMIC:
d4a79f9a 624 return (*((const RangeQuery*)range))();
7db3d57c
RC
625
626 default:
627 break;
628 }
d4a79f9a 629 return (const char*)range;
7db3d57c
RC
630}
631
b58b2e80
RC
632bool Parameter::get_bool() const
633{
634 if ( !deflt )
635 return false;
636
637 return ( strchr(deflt, 't') || strchr(deflt, 'T') );
638}
639
640double Parameter::get_number() const
641{
642 if ( !deflt )
643 return 0;
644
645 return strtod(deflt, nullptr);
646}
647
648const char* Parameter::get_string() const
649{
650 return deflt ? deflt : "";
651}
652
4b9776eb
RC
653const Parameter* Parameter::find(const Parameter* p, const char* s)
654{
127945e5
RC
655 if ( !p )
656 return nullptr;
657
4b9776eb
RC
658 while ( p->name )
659 {
3a20f1b0 660 if ( !strcmp(p->name, s) || p->is_wild_card() )
4b9776eb
RC
661 return p;
662 ++p;
663 }
664 return nullptr;
665}
666
55dcf17f
RC
667int Parameter::index(const char* r, const char* s)
668{
669 const char* t = ::find(r, s);
670
671 if ( !t )
672 return -1;
673
674 unsigned idx = get_index(r, t);
675 return (int)idx;
676}
677
020356df
RC
678//--------------------------------------------------------------------------
679// valid_* tests
680// we only test validation here
681// side effects applied to value are tested elsewhere
682//--------------------------------------------------------------------------
683
6659401d
MA
684#ifdef CATCH_TEST_BUILD
685
686#include "catch/catch.hpp"
687
020356df
RC
688TEST_CASE("bool", "[Parameter]")
689{
690 Value v(true);
9d1d5865
RD
691 CHECK(true == valid_bool(v, nullptr));
692 CHECK(true == valid_interval(v, nullptr));
020356df
RC
693}
694
695struct
696{
697 bool expected;
9d1d5865 698 bool (*validate)(Value&, const char*);
020356df
RC
699 double value;
700 const char* range;
701}
702num_tests[] =
703{
704// __STRDUMP_DISABLE__
705 { true, valid_int, 0, nullptr },
706 { true, valid_int, 0, "" },
707 { true, valid_int, 0, "0" },
708 { true, valid_int, 0, "0:" },
709 { true, valid_int, 0, ":0" },
710 { true, valid_int, 0, ":1" },
711 { true, valid_int, 0, "-1:1" },
712 { true, valid_int, 0, "-1:" },
713
714 { false, valid_int, 1, "0" },
715 { true, valid_int, 1, "0:" },
716 { false, valid_int, 1, ":0" },
a478eca7
OSSIC
717 { true, valid_int, -1, "-1" },
718 { false, valid_int, 2, "-1" },
020356df 719
49af2b2c
RC
720 { false, valid_int, 1.5, ":0" },
721
020356df
RC
722 { true, valid_int, -10, "-11:-9" },
723 { true, valid_int, 10, "9:11" },
724 { true, valid_int, 10, "0xA:11" },
9d1d5865
RD
725 { true, valid_int, -11, ":-11" },
726 { true, valid_int, -30, ":-11" },
727 { false, valid_int, -10, ":-11" },
728 { false, valid_int, 10, ":-11" },
020356df 729
49af2b2c
RC
730 { true, valid_real, 0.0, nullptr },
731 { true, valid_real, 0.0, "" },
732 { true, valid_real, 0.0, "0.0" },
733 { true, valid_real, 0.0, ":0" },
734
735 { true, valid_real, 0.1, "0:" },
736 { true, valid_real, 0.1, ":0.9" },
737 { true, valid_real, 0.1, "-0.9:0.9" },
738 { true, valid_real, 0.1, "-0.9:" },
020356df
RC
739
740 { false, valid_real, 1, "0.9" },
741 { true, valid_real, 1, "0.9:" },
742 { false, valid_real, 1, ":0.9" },
743
744 { true, valid_real, -10, "-11.1:-9.9" },
745 { true, valid_real, 10, "9.9:11.1" },
746 { false, valid_real, 10, "011:11" },
747 { true, valid_real, 10, "0xA:11" },
748
749 { false, nullptr, 0, nullptr }
750// __STRDUMP_ENABLE__
751};
752
753TEST_CASE("num", "[Parameter]")
754{
755 auto test = num_tests;
756
757 while ( test->validate )
758 {
759 Value v(test->value);
760 bool result = test->validate(v, test->range);
761 CHECK(result == test->expected);
762 ++test;
763 }
764}
765
9d1d5865
RD
766struct
767{
768 bool expected;
769 bool (*validate)(Value&, const char*);
770 const char* value;
771 const char* range;
772}
773str_num_tests[] =
774{
775// __STRDUMP_DISABLE__
776 { true, valid_int, "5", "-53:53" },
777 { true, valid_int, "-9223372036854775808", "-9223372036854775808:9223372036854775807" },
778 { true, valid_int, "0x7fffffffffffffff", "-9223372036854775808:9223372036854775807" },
779 { true, valid_int, "9223372036854775806", "-9223372036854775808:9223372036854775807" },
780 { true, valid_int, "0", "-9223372036854775808:9223372036854775807" },
781 { false, valid_int, "9223372036854775807", "-9223372036854775808:9223372036854775806" },
782 { false, valid_int, "-9223372036854775808", "-9223372036854775807:9223372036854775806" },
783 { true, valid_int, "0", "0:18446744073709551615" },
784 { true, valid_int, "0", "0:18446744073709551614" },
785 { true, valid_int, "1024", "0:18446744073709551614" },
786 { true, valid_int, "18446744073709551614", "0:18446744073709551614" },
787 { false, valid_int, "18446744073709551615", "0:18446744073709551614" },
788 { true, valid_int, "18446744073709551615", "18446744073709551615" },
789 { true, valid_int, "18446744073709551615", "max64" },
790 { true, valid_int, "4294967295", "max32" },
791 { false, valid_int, "4294967296", "max32" },
792 { true, valid_int, "2147483647", "max31" },
793 { false, valid_int, "2147483648", "max31" },
794 { true, valid_int, "50", "50:50" },
795 { false, valid_int, "51", "50:50" },
796 { true, valid_int, "-50", "-50:-50" },
797 { false, valid_int, "51", "-50:-50" },
798 { false, valid_int, "-51", "-50:-50" },
799 { true, valid_int, "-53", ":-53" },
800 { true, valid_int, "-54", ":-53" },
801 { true, valid_int, "-9223372036854775808", ":-53" },
802 { false, valid_int, "-52", ":-53" },
803 { false, valid_int, "2", ":-53" },
804
a478eca7
OSSIC
805 { false, valid_int, "", "" },
806 { false, valid_int, "foo", "" },
807 { false, valid_int, "1a", "" },
808 { false, valid_int, "a1", "" },
809 { false, valid_int, " 1", "" },
810 { false, valid_int, "1 ", "" },
811 { false, valid_int, "\t\t2", "" },
812 { false, valid_int, "2\t\t", "" },
813 { false, valid_int, " -3", "" },
814 { false, valid_int, "-3 ", "" },
815 { false, valid_int, "4 5", "" },
816 { true, valid_int, "+10", "" },
817 { false, valid_int, "", "0:1" },
818 { false, valid_int, "foo", "0:1" },
819 { false, valid_int, "1a", "0:1" },
820 { false, valid_int, "a1", "0:1" },
821 { false, valid_int, " 1", "0:1" },
822 { false, valid_int, "1 ", "0:1" },
823 { false, valid_int, "\t\t2", "2:3" },
824 { false, valid_int, "2\t\t", "2:3" },
825 { false, valid_int, " -3", "-5:5" },
826 { false, valid_int, "-3 ", "-5:5" },
827 { false, valid_int, "4 5", "-5:5" },
828 { true, valid_int, "+10", "0:20" },
829
830 { true, valid_int, "max31", "" },
831 { true, valid_int, "max32", "" },
832 { true, valid_int, "max53", "" },
833 { true, valid_int, "max63", "" },
834 { true, valid_int, "max64", "" },
835 { true, valid_int, "max31", "max31" },
836 { false, valid_int, "max32", "max31" },
837
838 { false, valid_int, " max32", "" },
839 { false, valid_int, "max32 ", "" },
840 { false, valid_int, "maxN", "" },
841 { false, valid_int, "max31:max32", "" },
842
9d1d5865
RD
843 { true, valid_real, "0.0", "0.0" },
844 { true, valid_real, "0.0", ":0" },
845
846 { true, valid_real, "0.1", "0:" },
847 { true, valid_real, "0.1", ":0.9" },
848 { true, valid_real, "0.1", "-0.9:0.9" },
849 { true, valid_real, "0.1", "-0.9:" },
850
851 { false, valid_real, "1", "0.9" },
852 { true, valid_real, "1", "0.9:" },
853 { false, valid_real, "1", ":0.9" },
854
855 { true, valid_real, "-10", "-11.1:-9.9" },
856 { true, valid_real, "10", "9.9:11.1" },
857 { false, valid_real, "10", "011:11" },
858 { true, valid_real, "10", "0xA:11" },
859
860 { false, nullptr, 0, nullptr }
861// __STRDUMP_ENABLE__
862};
863
864TEST_CASE("str_num", "[Parameter]")
865{
866 auto test = str_num_tests;
867
868 while ( test->validate )
869 {
870 Value v(test->value);
871 bool result = test->validate(v, test->range);
872 CHECK(result == test->expected);
873 ++test;
874 }
875}
876
020356df
RC
877struct
878{
879 bool expected;
98a4cad5 880 bool (*validate)(const Value&, const char*);
020356df
RC
881 const char* value;
882 const char* range;
883}
98a4cad5 884const_string_tests[] =
020356df
RC
885{
886// __STRDUMP_DISABLE__
887 { true, valid_string, "green", "(optional)" },
888 { true, valid_string, "green", nullptr },
889 { true, valid_string, "green", "5" },
890 { true, valid_string, "green", "6" },
891 { false, valid_string, "green", "4" },
892
893 { true, valid_select, "green", "red | green | yellow" },
894 { false, valid_select, "blue", "red | green | yellow" },
895 { false, valid_select, "green", nullptr },
896
a524ad57 897 { false, nullptr, nullptr, nullptr }
98a4cad5
MA
898// __STRDUMP_ENABLE__
899};
900
901struct
902{
903 bool expected;
904 bool (*validate)(Value&, const char*);
905 const char* value;
906 const char* range;
907}
908string_tests[] =
909{
910// __STRDUMP_DISABLE__
020356df
RC
911 { true, valid_enum, "green", "red | green | yellow" },
912 { false, valid_enum, "blue", "red | green | yellow" },
913 { false, valid_enum, "green", nullptr },
914
915 { true, valid_multi, "green", "red | green | yellow" },
916 { true, valid_multi, "red yellow", "red | green | yellow" },
917 { false, valid_multi, "redgreen", "red | green | yellow" },
918 { false, valid_multi, "blue", nullptr },
919
920 { true, valid_mac, "98:01:a7:9d:d8:41", nullptr },
921 { false, valid_mac, ":01:a7:9d:d8:41", nullptr },
922 { false, valid_mac, "01:a7:9d:d8:41", nullptr },
923 { false, valid_mac, "98:01:a7:9d:d8:419", nullptr },
924 { false, valid_mac, "98:01:a7:9d:d8:41x", nullptr },
925
926 { true, valid_ip4, "1.2.3.4", nullptr },
927 { true, valid_ip4, "1.2.3", nullptr },
928 { false, valid_ip4, "1.2.3.", nullptr },
929 { false, valid_ip4, "1.2.x", nullptr },
930
931 { true, valid_addr, "1.2.3.4", nullptr },
932 { true, valid_addr, "1.2.3.4/32", nullptr },
933 { true, valid_addr, "1.2.3.4/0", nullptr },
934 { false, valid_addr, "1.2.3.4/33", nullptr },
935 { false, valid_addr, "1.2.0x.4/33", nullptr },
936
937 { true, valid_addr, "2001:420:c0c4:1004::157", nullptr },
938 { true, valid_addr, "2001:420:c0c4:1004::157/128", nullptr },
939 { true, valid_addr, "2001:420:c0c4:1004::157/0", nullptr },
940 { false, valid_addr, "2001:420:c0c4:1004:0x:157/256", nullptr },
941
942 { true, valid_bit_list, "1 2", "3" },
943 { true, valid_bit_list, "1 2 3", "3" },
944 { false, valid_bit_list, "1 2 3 4", "3" },
945 { false, valid_bit_list, "128", "3" },
946
c06c8d5e 947 { true, valid_int_list, "0 65535", nullptr },
948 { true, valid_int_list, "0 65535", "65535" },
949 { false, valid_int_list, "-1", "1" },
950 { false, valid_int_list, "65535", "1" },
951 { false, valid_int_list, "1", "0" },
952 { true, valid_int_list, "0", "0" },
953
a524ad57 954 { false, nullptr, nullptr, nullptr }
020356df
RC
955// __STRDUMP_ENABLE__
956};
957
958TEST_CASE("string", "[Parameter]")
959{
98a4cad5
MA
960 auto ctest = const_string_tests;
961 while ( ctest->validate )
962 {
963 Value v(ctest->value);
964 bool result = ctest->validate(v, ctest->range);
965 CHECK(result == ctest->expected);
966 ++ctest;
967 }
020356df 968
98a4cad5 969 auto test = string_tests;
020356df
RC
970 while ( test->validate )
971 {
972 Value v(test->value);
973 bool result = test->validate(v, test->range);
974 CHECK(result == test->expected);
975 ++test;
976 }
977}
978
979TEST_CASE("max", "[Parameter]")
980{
f990379d
BT
981 CHECK(Parameter::get_int("max31") == 2147483647);
982 CHECK(Parameter::get_int("max32") == 4294967295);
983 CHECK(Parameter::get_int("max53") == 9007199254740992);
9d1d5865
RD
984 CHECK(Parameter::get_int("max63") == 9223372036854775807);
985 CHECK(Parameter::get_int("max64") == -1);
020356df
RC
986
987 if ( sizeof(size_t) == 4 )
f990379d 988 CHECK(Parameter::get_int("maxSZ") == 4294967295);
020356df 989 else
f990379d 990 CHECK(Parameter::get_int("maxSZ") == 9007199254740992);
9d1d5865
RD
991
992 CHECK(Parameter::get_uint("max31") == 2147483647);
993 CHECK(Parameter::get_uint("max32") == 4294967295);
994 CHECK(Parameter::get_uint("max53") == 9007199254740992);
995 CHECK(Parameter::get_uint("max63") == 9223372036854775807);
996 CHECK(Parameter::get_uint("max64") == 18446744073709551615ULL);
997
998 if ( sizeof(size_t) == 4 )
999 CHECK(Parameter::get_uint("maxSZ") == 4294967295);
1000 else
1001 CHECK(Parameter::get_uint("maxSZ") == 9007199254740992);
020356df 1002}
6659401d 1003
020356df
RC
1004#endif
1005