#![allow(unused_variables)]
use super::super::*;
use std::collections::HashMap;
use std::fmt;
macro_rules! matches {
($e:expr, $p:pat) => {
match $e {
$p => true,
_ => false,
}
};
}
fn run_tests<T: fmt::Display, F: FnMut(&str, &HashMap<String, T>) -> Result<String>>(
values: &Vec<(&str, &str, u8)>,
vars: &HashMap<String, T>,
call: F,
) {
let mut call = call;
for &(fmtstr, expected, expect_err) in values.iter() {
let result = call(fmtstr, vars);
let mut failure = match expect_err {
0 => result.is_err(),
1 => !matches!(result, Err(FmtError::Invalid(_))),
2 => !matches!(result, Err(FmtError::KeyError(_))),
3 => !matches!(result, Err(FmtError::TypeError(_))),
c @ _ => panic!("error code {} DNE", c),
};
let result = match result {
Err(e) => e.to_string(),
Ok(s) => s,
};
if !failure && expect_err == 0 {
failure = !(expected == result);
}
if failure {
println!("FAIL:");
println!(" input: {:?}", fmtstr);
println!(" output: {:?}", result);
if expect_err != 0 {
let expected = match expect_err {
1 => "FmtError::Invalid",
2 => "FmtError::KeyError",
3 => "FmtError::TypeError",
_ => unreachable!(),
};
println!(" expected: {}", expected)
} else {
println!(" expected: {:?}", expected);
}
assert!(false);
}
}
}
#[test]
fn test_values() {
let mut vars: HashMap<String, String> = HashMap::new();
let too_long = "toooloooong".to_string();
let rust_unicode = format!(">{:^7}<", "ಠ_ಠ");
vars.insert("x".to_string(), "X".to_string());
vars.insert("long".to_string(), too_long.clone()); vars.insert("hi".to_string(), "hi".to_string());
vars.insert("unicode".to_string(), "ಠ_ಠ".to_string());
let values: Vec<(&str, &str, u8)> = vec![
("{x}", "X", 0),
("{x:}", "X", 0),
("{x:3}", "X ", 0),
("{x:>3}", " X", 0),
("{x:<3}", "X ", 0),
("{x:^3}", " X ", 0),
("{x:^4}", " X ", 0),
(" {x}yz", " Xyz", 0),
(" hi {x:^4}-you rock", " hi X -you rock", 0),
(">{unicode:^7}<", "> ಠ_ಠ <", 0),
(">{unicode:^7}<", &rust_unicode, 0),
("{unicode:<5}", "ಠ_ಠ ", 0),
("{unicode:>5}", " ಠ_ಠ", 0),
("{x:10}", "X ", 0),
("{x:>10}", " X", 0),
("{x:0<5}", "X0000", 0),
("{x:0>5}", "0000X", 0),
("{long:.3}", "too", 0),
("{long:5.3}", "too ", 0),
("{long:>5.3}", " too", 0),
("{long:5.7}", "toooloo", 0),
("{long:<5.7}", "toooloo", 0),
("{long:>5.7}", "toooloo", 0),
("{long:^5.7}", "toooloo", 0),
("{long:<}", &too_long, 0),
("{long:<<}", &too_long, 0),
("{long:<<5}", &too_long, 0),
("{x:<4s}", "X ", 0),
("{{}}", "{}", 0),
("{{long}}", "{long}", 0),
("{{{x}}}", "{X}", 0),
("{x:<>}", "X", 0),
("{x:<>3}", "<<X", 0),
("{{}}", "{}", 0),
("{{{x}}}", "{X}", 0),
("{{{x}{{{{{{", "{X{{{", 0),
("{x}}}}}", "X}}", 0),
("{}", "", 1),
("{:3}", "", 1),
("{xxx: <88.3}", "", 1),
("}", "", 1),
("{{}}}", "", 1),
("hi } there", "", 1),
("hi }", "", 1),
("w { ho", "", 1),
("{what}", "{}", 2),
("{who}", "{}", 2),
("{x} {where}", "{}", 2),
("{x:<<<}", "", 3),
("{x:*}", "", 3),
("{x::}", "", 3),
("{x:#}", "", 3),
("{x:<4n}", "", 3),
("{x:<4d}", "", 3),
("{x:,}", "", 3),
("{x:<-10}", "", 3),
("{x:0=5}", "00X00", 1),
("{x:03}", "00X", 1),
];
run_tests(&values, &vars, &strfmt);
}
#[test]
fn test_ints_basic() {
let mut vars: HashMap<String, u64> = HashMap::new();
vars.insert("x".to_string(), 6);
vars.insert("long".to_string(), 100000); vars.insert("hi".to_string(), 42);
let values: Vec<(&str, &str, u8)> = vec![
("{x}", "6", 0),
("{long}", "100000", 0),
(
" the answer is {hi}, haven't you read anything?",
" the answer is 42, haven't you read anything?",
0,
),
];
run_tests(&values, &vars, &strfmt);
}
#[test]
fn test_ignore_missing() {
let mut vars: HashMap<String, String> = HashMap::new();
vars.insert("x".to_string(), "X".to_string());
let values: Vec<(&str, &str, u8)> = vec![
("{y}", "{y}", 0),
("{y} {x}", "{y} X", 0),
(
"{x} {longish:<32.3} {x} is nice",
"X {longish:<32.3} X is nice",
0,
),
];
let f = |mut fmt: Formatter| match vars.get(fmt.key) {
Some(v) => fmt.str(v),
None => fmt.skip(),
};
let strfmt_ignore =
|fmtstr: &str, vars: &HashMap<String, String>| -> Result<String> { strfmt_map(fmtstr, &f) };
run_tests(&values, &vars, &strfmt_ignore);
}
#[test]
fn test_mut_closure() {
let mut key_list = vec![];
let f = |fmt: Formatter| {
match fmt.key.parse::<String>() {
Ok(key) => {
key_list.push(key);
},
Err(_) => {
return Err(FmtError::KeyError(format!("Invalid key: {}", fmt.key)));
}
};
fmt.skip()
};
let _ = strfmt_map("{one} two {three:4.4}", f).unwrap();
assert_eq!(key_list, vec!["one", "three"]);
}
#[test]
fn test_trailing_comma() {
assert!(strfmt!("{foo}", foo => "bar", ) == Ok("bar".into()));
let foo = "bar";
assert!(strfmt!("{foo}", foo,) == Ok("bar".into()));
}
macro_rules! test_float {
($($name:ident $t:ident),*) => ($(
#[test]
fn $name() {
let mut vars: HashMap<String, $t> = HashMap::new();
vars.insert("x".to_string(), 42.4242);
vars.insert("y".to_string(), -100.11111);
vars.insert("z".to_string(), 0.);
let values: Vec<(&str, &str, u8)> = vec![
("{x}", "42.4242", 0),
("{x:.2}", "42.42", 0),
("{x:<7.2}", "42.42 ", 0),
("{x:.2e}", "4.24e1", 0),
("{x:.2E}", "4.24E1", 0),
("{x:+}", "+42.4242", 0),
("{y:.2E}", "-1.00E2", 0),
("{y:+.2E}", "-1.00E2", 0),
("{z:+.2E}", "+0.00E0", 0),
("{x:s}", "", 3),
("{x:#}", "", 3),
("{x:+010.2}", "+0042.4242", 1),
];
let f = |mut fmt: Formatter| {
match vars.get(fmt.key) {
Some(v) => fmt.$t(*v),
None => panic!(),
}
};
let strfmt_float = |fmtstr: &str, vars: &HashMap<String, $t>| -> Result<String> {
strfmt_map(fmtstr, &f)
};
run_tests(&values, &vars, &strfmt_float);
}
)*)
}
test_float!(test_f32 f32, test_f64 f64);
macro_rules! test_uint {
($($name:ident $t:ident),*) => ($(
#[test]
fn $name() {
let mut vars: HashMap<String, $t> = HashMap::new();
vars.insert("x".to_string(), 42);
vars.insert("y".to_string(), 0);
let values: Vec<(&str, &str, u8)> = vec![
("{x}", "42", 0),
("{x:<7}", "42 ", 0),
("{x:>7}", " 42", 0),
("{x:^7}", " 42 ", 0),
("{x:x}", "2a", 0),
("{x:X}", "2A", 0),
("{x:+x}", "+2a", 0),
("{x:#x}", "0x2a", 0),
("{x:#X}", "0x2A", 0),
("{x:b}", "101010", 0),
("{x:#b}", "0b101010", 0),
("{x:o}", "52", 0),
("{x:#o}", "0o52", 0),
("{x:+}", "+42", 0),
("{y:-}", "0", 0),
("{y:+}", "+0", 0),
("{x:.2}", "", 3),
("{x:s}", "", 3),
("{x:+010}", "+000000042", 1),
];
let f = |mut fmt: Formatter| {
match vars.get(fmt.key) {
Some(v) => fmt.$t(*v),
None => panic!(),
}
};
let strfmt_int = |fmtstr: &str, vars: &HashMap<String, $t>| -> Result<String> {
strfmt_map(fmtstr, &f)
};
run_tests(&values, &vars, &strfmt_int);
}
)*)
}
macro_rules! test_int {
($($name:ident $t:ident),*) => ($(
#[test]
fn $name() {
let mut vars: HashMap<String, $t> = HashMap::new();
vars.insert("x".to_string(), 42);
vars.insert("y".to_string(), -100);
vars.insert("z".to_string(), 0);
let values: Vec<(&str, &str, u8)> = vec![
("{x}", "42", 0),
("{x:<7}", "42 ", 0),
("{x:X}", "2A", 0),
("{x:#x}", "0x2a", 0),
("{x:#X}", "0x2A", 0),
("{x:b}", "101010", 0),
("{x:#b}", "0b101010", 0),
("{x:o}", "52", 0),
("{x:#o}", "0o52", 0),
("{x:+}", "+42", 0),
("{y}", "-100", 0),
("{y:+}", "-100", 0),
("{z}", "0", 0),
("{z:-}", "0", 0),
("{z:+}", "+0", 0),
("{x:.2}", "", 3),
("{x:s}", "", 3),
("{x:+010}", "+000000042", 1),
];
let f = |mut fmt: Formatter| {
match vars.get(fmt.key) {
Some(v) => fmt.$t(*v),
None => panic!(),
}
};
let strfmt_uint = |fmtstr: &str, vars: &HashMap<String, $t>| -> Result<String> {
strfmt_map(fmtstr, &f)
};
run_tests(&values, &vars, &strfmt_uint);
}
)*)
}
test_uint!(test_u8 u8, test_u16 u16, test_u32 u32, test_u64 u64, test_usize usize);
test_int!(test_i8 i8, test_i16 i16, test_i32 i32, test_i64 i64, test_isize isize);