use crate::model::Part::Specification;
use crate::parser::parse_format;
use crate::writer::spec_to_ansi;
pub fn cprintf(inputs: Vec<String>) -> Result<String, String> {
let parsed = parse_format(&inputs[0]);
match parsed {
Err(m) => Err(m.to_string()),
Ok(specs) => {
let has_specifiers = specs.iter().any(|it|
match it {
Specification { text: _, color: _, styles: _ } => true,
_ => false
});
if inputs.len() < 2 && (has_specifiers || inputs[0].is_empty()) {
Err("The minimum number of arguments is 2. The first argument is the format. If no formatting is necessary, use an empty string.".to_string())
} else if inputs[0].is_empty() {
let mut result = inputs[1].to_string();
inputs.iter().skip(2).for_each(|s| result.push_str(s));
Ok(result)
} else {
spec_to_ansi(&inputs, specs)
}
}
}
}
#[cfg(test)]
mod tests {
use crate::vecs;
use crate::cprintf::cprintf;
#[test]
fn check_that_there_is_at_least_2_arguments_when_there_is_1_spec() {
let i = vecs!("{}");
let actual = cprintf(i);
assert_eq!(
actual.err(),
Some("The minimum number of arguments is 2. The first argument is the format. If no formatting is necessary, use an empty string.".to_string())
)
}
#[test]
fn print_formatted_string_with_positional_arguments() {
let actual = cprintf(vecs!("{}+{}={}", "1", "2", "3"));
assert_eq!(actual.unwrap(), "1+2=3\x1b[0m".to_string());
}
#[test]
fn when_the_first_string_is_empty_and_there_are_2_arguments_just_return_the_second_argument() {
let i = vecs!("", "{foo}");
let actual = cprintf(i);
assert_eq!(actual.ok(), Some("{foo}".to_string()));
}
#[test]
fn when_the_first_string_is_empty_and_there_are_n_arguments_just_return_their_concatenation() {
let i = vecs!("", "1", ", 2, ", "N...");
let actual = cprintf(i);
assert_eq!(actual.ok(), Some("1, 2, N...".to_string()));
}
#[test]
fn when_a_format_is_specified_then_use_it_0_spec() {
let i = vecs!(
r#"Just raw text, nothing special, no placeholder like \{\}"#,
"this will be ignored because the format contains no formatting specifier"
);
let actual = cprintf(i);
assert_eq!(actual.ok(), Some("Just raw text, nothing special, no placeholder like {}\x1b[0m".to_string()));
}
#[test]
fn when_a_format_is_specified_then_use_it_2_specs() {
let i = vecs!("{} and {}", "A", "B");
let actual = cprintf(i);
assert_eq!(actual.ok(), Some("A and B\x1b[0m".to_string()));
}
#[test]
fn print_red() {
let i = vecs!("{#r}", "red");
let actual = cprintf(i);
assert_eq!(actual.ok(), Some("\x1b[31mred\x1b[0m\x1b[0m".to_string()));
}
#[test]
fn print_green() {
let i = vecs!("{#g}", "green");
let actual = cprintf(i);
assert_eq!(actual.ok(), Some("\x1b[32mgreen\x1b[0m\x1b[0m".to_string()));
}
#[test]
fn tolerate_missing_arguments_when_the_format_doesnt_contain_specs() {
let i = vecs!(r#"\{}"#);
let actual = cprintf(i);
assert_eq!(actual.ok(), Some("{}\x1b[0m".to_string()));
}
#[test]
fn a_single_empty_string_as_the_single_argument_is_valid_and_does_nothing() {
let i = vecs!("");
let actual = cprintf(i);
assert_eq!(actual.ok(), None);
}
}