Skip to content

Commit db1f41f

Browse files
Validate "seconds" command line options
- Validate the `--polling-interval` command line option - Validate the `--timeout` command line option - Validate the `--ttl` command line option Issue #56
1 parent 6473fd0 commit db1f41f

File tree

1 file changed

+136
-9
lines changed

1 file changed

+136
-9
lines changed

src/options.rs

+136-9
Original file line numberDiff line numberDiff line change
@@ -21,22 +21,54 @@ pub struct DaemonOpts {
2121
pub common: CommonOpts, // cov(skip)
2222

2323
/// Change detection polling interval in seconds
24-
#[structopt(short = "p", long = "poll", default_value = "30")]
24+
#[structopt(
25+
short = "p", long = "poll", default_value = "30",
26+
validator = validate_polling_interval)]
2527
pub polling_interval: u64,
2628

2729
/// Log to syslog (vice console)
2830
#[structopt(long = "syslog")]
2931
pub syslog: bool, // cov(skip)
3032

3133
/// Avahi D-Bus connection timeout
32-
#[structopt(long = "timeout", default_value = "60")]
34+
#[structopt(long = "timeout", default_value = "60", validator = validate_timeout)]
3335
pub timeout: u64,
3436

3537
/// Alias mDNS time-to-live (TTL) in seconds
36-
#[structopt(long = "ttl", default_value = "60")]
38+
#[structopt(long = "ttl", default_value = "60", validator = validate_ttl)]
3739
pub ttl: u64,
3840
}
3941

42+
fn validate_polling_interval(value: String) -> Result<(), String> {
43+
match value.parse::<u64>() {
44+
Err(error) => Err(error.to_string()),
45+
Ok(timeout) if !(10..=60).contains(&timeout) => {
46+
Err("polling interval must be 10-60 seconds".to_string())
47+
},
48+
_ => Ok(()),
49+
}
50+
}
51+
52+
fn validate_timeout(value: String) -> Result<(), String> {
53+
match value.parse::<u64>() {
54+
Err(error) => Err(error.to_string()),
55+
Ok(timeout) if !(10..=300).contains(&timeout) => {
56+
Err("timeout must be 10-300 seconds".to_string())
57+
},
58+
_ => Ok(()),
59+
}
60+
}
61+
62+
fn validate_ttl(value: String) -> Result<(), String> {
63+
match value.parse::<u64>() {
64+
Err(error) => Err(error.to_string()),
65+
Ok(timeout) if timeout > (i32::MAX as u64) => {
66+
Err("time-to-live (TTL) must be less than 2,147,483,648 (2^31) seconds".to_string())
67+
},
68+
_ => Ok(()),
69+
}
70+
}
71+
4072
#[derive(Debug, StructOpt)]
4173
pub struct CommonOpts {
4274
/// Prints detailed messages
@@ -377,22 +409,117 @@ mod tests {
377409
}
378410

379411
#[test]
380-
fn daemon_timeout_option_works() {
381-
let opts = DaemonOpts::from_iter(["", "--timeout", "100"]);
382-
assert_eq!(opts.timeout, 100);
412+
fn polling_interval_validation_returns_ok_for_in_range_values() {
413+
assert!(validate_polling_interval(String::from("10")).is_ok());
414+
assert!(validate_polling_interval(String::from("30")).is_ok());
415+
assert!(validate_polling_interval(String::from("60")).is_ok());
383416
}
384417

385418
#[test]
386-
fn daemon_ttl_option_works() {
387-
let opts = DaemonOpts::from_iter(["", "--ttl", "100"]);
388-
assert_eq!(opts.ttl, 100);
419+
fn polling_interval_validation_returns_error_for_out_of_range_values() {
420+
assert!(validate_polling_interval(String::from("0")).is_err());
421+
assert!(validate_polling_interval(String::from("9")).is_err());
422+
assert!(validate_polling_interval(String::from("61")).is_err());
423+
assert!(validate_polling_interval(String::from("120")).is_err());
424+
}
425+
426+
#[test]
427+
fn polling_interval_validation_returns_error_for_invalid_values() {
428+
assert!(validate_polling_interval(String::from("not-a-number")).is_err());
429+
}
430+
431+
#[test]
432+
fn polling_interval_validation_returns_correct_message_on_error() {
433+
assert_eq!(
434+
validate_polling_interval(String::from("0")).unwrap_err(),
435+
"polling interval must be 10-60 seconds"
436+
);
437+
assert_eq!(
438+
validate_polling_interval(String::from("not-a-number")).unwrap_err(),
439+
"invalid digit found in string"
440+
);
441+
}
442+
443+
#[test]
444+
fn timeout_validation_returns_ok_for_in_range_values() {
445+
assert!(validate_timeout(String::from("10")).is_ok());
446+
assert!(validate_timeout(String::from("60")).is_ok());
447+
assert!(validate_timeout(String::from("300")).is_ok());
448+
}
449+
450+
#[test]
451+
fn timeout_validation_returns_error_for_out_of_range_values() {
452+
assert!(validate_timeout(String::from("0")).is_err());
453+
assert!(validate_timeout(String::from("9")).is_err());
454+
assert!(validate_timeout(String::from("301")).is_err());
455+
assert!(validate_timeout(String::from("600")).is_err());
456+
}
457+
458+
#[test]
459+
fn timeout_validation_returns_error_for_invalid_values() {
460+
assert!(validate_timeout(String::from("not-a-number")).is_err());
461+
}
462+
463+
#[test]
464+
fn timeout_validation_returns_correct_message_on_error() {
465+
assert_eq!(
466+
validate_timeout(String::from("0")).unwrap_err(),
467+
"timeout must be 10-300 seconds"
468+
);
469+
assert_eq!(
470+
validate_timeout(String::from("not-a-number")).unwrap_err(),
471+
"invalid digit found in string"
472+
);
473+
}
474+
475+
#[test]
476+
fn ttl_validation_returns_ok_for_in_range_values() {
477+
assert!(validate_ttl(String::from("0")).is_ok());
478+
assert!(validate_ttl(String::from("30")).is_ok());
479+
assert!(validate_ttl(String::from("86400")).is_ok());
480+
assert!(validate_ttl(i32::MAX.to_string()).is_ok());
481+
}
482+
483+
#[test]
484+
fn ttl_validation_returns_error_for_out_of_range_values() {
485+
assert!(validate_ttl(((i32::MAX as u64) + 1).to_string()).is_err());
486+
assert!(validate_ttl(u64::MAX.to_string()).is_err());
487+
}
488+
489+
#[test]
490+
fn ttl_validation_returns_error_for_invalid_values() {
491+
assert!(validate_ttl(String::from("not-a-number")).is_err());
492+
}
493+
494+
#[test]
495+
fn ttl_validation_returns_correct_message_on_error() {
496+
assert_eq!(
497+
validate_ttl(((i32::MAX as u64) + 1).to_string()).unwrap_err(),
498+
"time-to-live (TTL) must be less than 2,147,483,648 (2^31) seconds"
499+
);
500+
assert_eq!(
501+
validate_ttl(String::from("not-a-number")).unwrap_err(),
502+
"invalid digit found in string"
503+
);
389504
}
390505

391506
#[test]
392507
fn daemon_syslog_option_works() {
393508
let opts = DaemonOpts::from_iter(["", "--syslog"]);
394509
assert!(opts.syslog);
395510
}
511+
512+
#[test]
513+
fn daemon_timeout_option_works() {
514+
let opts = DaemonOpts::from_iter(["", "--timeout", "100"]);
515+
assert_eq!(opts.timeout, 100);
516+
}
517+
518+
#[test]
519+
fn daemon_ttl_option_works() {
520+
let opts = DaemonOpts::from_iter(["", "--ttl", "100"]);
521+
assert_eq!(opts.ttl, 100);
522+
}
396523
}
397524

398525
// end

0 commit comments

Comments
 (0)