use epics_base_rs::calc::{CalcError, StackValue, StringInputs, scalc};
fn pf(expr: &str) -> String {
let mut inp = StringInputs::new();
match scalc(expr, &mut inp).expect("st=0") {
StackValue::Str(s) => s.as_str_lossy().into_owned(),
StackValue::Double(d) => panic!("PRINTF is a string, got {d}"),
}
}
fn pf_str(fmt: &str, arg: &str) -> String {
let mut inp = StringInputs::new();
inp.str_vars[0] = arg.into();
match scalc(&format!("PRINTF(\"{fmt}\", AA)"), &mut inp).expect("st=0") {
StackValue::Str(s) => s.as_str_lossy().into_owned(),
StackValue::Double(d) => panic!("PRINTF is a string, got {d}"),
}
}
#[test]
fn a_format_with_no_live_conversion_is_copied_verbatim() {
assert_eq!(pf("PRINTF(\"%d%%\", 5)"), "%d%%");
assert_eq!(pf("PRINTF(\"100%%\", 5)"), "100%%");
assert_eq!(pf("PRINTF(\"%.2f%%\", 3.14159)"), "%.2f%%");
assert_eq!(pf("PRINTF(\"50%% done\", 1)"), "50%% done");
assert_eq!(pf("PRINTF(\"no conv\", 1)"), "no conv");
assert_eq!(pf("PRINTF(\"%\", 1)"), "%");
assert_eq!(pf("PRINTF(\"%z\", 1)"), "%z");
}
#[test]
fn a_live_conversion_collapses_the_earlier_double_percents() {
assert_eq!(pf("PRINTF(\"a%%b %5.2f!\", 3.14159)"), "a%b 3.14!");
}
#[test]
fn width_flags_and_precision_are_snprintfs() {
assert_eq!(pf("PRINTF(\"%5.2f\", 3.14159)"), " 3.14");
assert_eq!(pf("PRINTF(\"%-8dX\", 42)"), "42 X");
assert_eq!(pf("PRINTF(\"%05d\", 42)"), "00042");
assert_eq!(pf("PRINTF(\"%+d\", 5)"), "+5");
assert_eq!(pf("PRINTF(\"% d\", 5)"), " 5");
assert_eq!(pf("PRINTF(\"%10.3e|\", 1234.5)"), " 1.234e+03|");
assert_eq!(pf("PRINTF(\"%e\", 1234.5678)"), "1.234568e+03");
assert_eq!(pf("PRINTF(\"%E\", 1234.5678)"), "1.234568E+03");
assert_eq!(pf("PRINTF(\"%g\", 0.0001)"), "0.0001");
assert_eq!(pf("PRINTF(\"%g\", 0.0000001)"), "1e-07");
assert_eq!(pf("PRINTF(\"%G\", 0.0000001)"), "1E-07");
assert_eq!(pf("PRINTF(\"%#g\", 1.5)"), "1.50000");
assert_eq!(pf("PRINTF(\"%#.0f\", 2)"), "2.");
assert_eq!(pf("PRINTF(\"%.0f\", 2.5)"), "2");
assert_eq!(pf("PRINTF(\"%.0f\", 3.5)"), "4");
}
#[test]
fn the_integer_conversions_are_c_ints() {
assert_eq!(pf("PRINTF(\"%d\", 2.6)"), "3");
assert_eq!(pf("PRINTF(\"%d\", -2.6)"), "-3");
assert_eq!(pf("PRINTF(\"%x\", -1)"), "ffffffff");
assert_eq!(pf("PRINTF(\"%u\", -1)"), "4294967295");
assert_eq!(pf("PRINTF(\"%X\", 255)"), "FF");
assert_eq!(pf("PRINTF(\"%#x\", 255)"), "0xff");
assert_eq!(pf("PRINTF(\"%o\", 8)"), "10");
assert_eq!(pf("PRINTF(\"%c\", 65)"), "A");
}
#[test]
fn the_string_conversion_takes_width_and_precision() {
assert_eq!(pf_str("%s|", "abc"), "abc|");
assert_eq!(pf_str("%8s|", "abc"), " abc|");
assert_eq!(pf_str("%-8s|", "abc"), "abc |");
assert_eq!(pf_str("%.2s|", "abcdef"), "ab|");
assert_eq!(pf_str("x%%y%s", "abc"), "x%yabc");
}
#[test]
fn a_suppressed_conversion_fails_the_perform() {
let mut inp = StringInputs::new();
assert!(matches!(
scalc("PRINTF(\"%*d\", 42)", &mut inp),
Err(CalcError::InvalidFormat)
));
}
#[test]
fn the_result_is_still_a_bounded_scalc_string() {
let mut inp = StringInputs::new();
assert!(
scalc("PRINTF(1, 2)", &mut inp).is_err(),
"format must be a string"
);
assert_eq!(pf("PRINTF(\"%50.2f\", 1)").len(), 38);
}