#[derive(Debug, Clone, PartialEq)]
pub enum ParamValue {
Float(f64),
String(String),
}
pub fn needs_quoting(value: &str) -> bool {
if value.is_empty() {
return true;
}
if value.parse::<f64>().is_ok() {
return true;
}
if value != value.trim() {
return true;
}
let lower = value.to_lowercase();
if lower == "true"
|| lower == "false"
|| lower == "null"
|| lower == "yes"
|| lower == "no"
|| lower == "on"
|| lower == "off"
{
return true;
}
if value.contains(':')
|| value.contains('#')
|| value.contains('{')
|| value.contains('}')
|| value.contains('[')
|| value.contains(']')
|| value.contains('"')
|| value.contains('\'')
|| value.contains('\\')
|| value.contains('\n')
{
return true;
}
false
}
pub fn escape_yaml_double_quoted(s: &str) -> String {
s.replace('\\', "\\\\").replace('"', "\\\"")
}
pub fn format_float(v: f64) -> String {
if v == v.trunc() && v.abs() < 1e15 {
format!("{:.1}", v) } else {
format!("{}", v) }
}
pub fn format_rate(rate: f64) -> String {
if rate == rate.trunc() && rate >= 1.0 {
format!("{}", rate as u64)
} else {
format!("{}", rate)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn needs_quoting_empty_string() {
assert!(needs_quoting(""));
}
#[test]
fn needs_quoting_numeric_string() {
assert!(needs_quoting("42"));
assert!(needs_quoting("3.14"));
}
#[test]
fn needs_quoting_boolean_keywords() {
assert!(needs_quoting("true"));
assert!(needs_quoting("false"));
assert!(needs_quoting("yes"));
assert!(needs_quoting("no"));
assert!(needs_quoting("null"));
}
#[test]
fn needs_quoting_colon() {
assert!(needs_quoting("http://example.com"));
}
#[test]
fn needs_quoting_hash() {
assert!(needs_quoting("value # comment"));
}
#[test]
fn needs_quoting_braces() {
assert!(needs_quoting("{key}"));
assert!(needs_quoting("value}"));
}
#[test]
fn needs_quoting_double_quote() {
assert!(needs_quoting(r#"say "hello""#));
}
#[test]
fn needs_quoting_backslash() {
assert!(needs_quoting(r"C:\Users\admin"));
}
#[test]
fn needs_quoting_square_brackets() {
assert!(needs_quoting("[item]"));
assert!(needs_quoting("value]"));
}
#[test]
fn needs_quoting_single_quote() {
assert!(needs_quoting("it's"));
}
#[test]
fn needs_quoting_newline() {
assert!(needs_quoting("line1\nline2"));
}
#[test]
fn needs_quoting_leading_trailing_whitespace() {
assert!(needs_quoting(" leading"));
assert!(needs_quoting("trailing "));
assert!(needs_quoting(" both "));
}
#[test]
fn needs_quoting_yaml_11_booleans() {
assert!(needs_quoting("on"));
assert!(needs_quoting("off"));
assert!(needs_quoting("On"));
assert!(needs_quoting("OFF"));
}
#[test]
fn no_quoting_for_plain_identifiers() {
assert!(!needs_quoting("web-01"));
assert!(!needs_quoting("node_exporter"));
assert!(!needs_quoting("eth0"));
}
#[test]
fn escape_no_special_chars() {
assert_eq!(escape_yaml_double_quoted("hello world"), "hello world");
}
#[test]
fn escape_double_quotes() {
assert_eq!(
escape_yaml_double_quoted(r#"say "hello""#),
r#"say \"hello\""#
);
}
#[test]
fn escape_backslash() {
assert_eq!(
escape_yaml_double_quoted(r"path\to\file"),
r"path\\to\\file"
);
}
#[test]
fn escape_both_backslash_and_quotes() {
assert_eq!(escape_yaml_double_quoted(r#"a\"b"#), r#"a\\\"b"#);
}
#[test]
fn format_float_integer_value() {
assert_eq!(format_float(50.0), "50.0");
}
#[test]
fn format_float_fractional_value() {
assert_eq!(format_float(3.14159), "3.14159");
}
#[test]
fn format_float_zero() {
assert_eq!(format_float(0.0), "0.0");
}
#[test]
fn format_rate_whole_number() {
assert_eq!(format_rate(1.0), "1");
assert_eq!(format_rate(10.0), "10");
}
#[test]
fn format_rate_fractional() {
assert_eq!(format_rate(0.5), "0.5");
}
#[test]
fn format_rate_sub_one() {
assert_eq!(format_rate(0.1), "0.1");
}
}