use crate::cli::{CountMode, DisplayMode};
use crate::counter::Count;
use crate::output::calculate_total;
use std::fmt::Write;
pub fn format(results: &[(String, Count)], display: DisplayMode, mode: CountMode) -> String {
let mut output = String::new();
writeln!(output, "{}", format_header(mode)).unwrap();
if display == DisplayMode::Total && results.len() > 1 {
let total = calculate_total(results);
write_row(&mut output, "total", &total, mode);
} else {
for (name, count) in results {
write_row(&mut output, name, count, mode);
}
}
output
}
const fn format_header(mode: CountMode) -> &'static str {
match mode {
CountMode::Both => "file,words,characters",
CountMode::Words => "file,words",
CountMode::Characters => "file,characters",
}
}
fn write_row(output: &mut String, name: &str, count: &Count, mode: CountMode) {
let row = match mode {
CountMode::Both => format!("{},{},{}", name, count.words, count.characters),
CountMode::Words => format!("{},{}", name, count.words),
CountMode::Characters => format!("{},{}", name, count.characters),
};
writeln!(output, "{row}").unwrap();
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_format_header_both() {
let header = format_header(CountMode::Both);
assert_eq!(header, "file,words,characters");
}
#[test]
fn test_format_header_words_only() {
let header = format_header(CountMode::Words);
assert_eq!(header, "file,words");
}
#[test]
fn test_format_header_characters_only() {
let header = format_header(CountMode::Characters);
assert_eq!(header, "file,characters");
}
#[test]
fn test_write_row_both() {
let mut output = String::new();
let count = Count {
words: 100,
characters: 500,
};
write_row(&mut output, "test.typ", &count, CountMode::Both);
assert_eq!(output, "test.typ,100,500\n");
}
#[test]
fn test_write_row_words_only() {
let mut output = String::new();
let count = Count {
words: 100,
characters: 500,
};
write_row(&mut output, "test.typ", &count, CountMode::Words);
assert_eq!(output, "test.typ,100\n");
}
#[test]
fn test_write_row_characters_only() {
let mut output = String::new();
let count = Count {
words: 100,
characters: 500,
};
write_row(&mut output, "test.typ", &count, CountMode::Characters);
assert_eq!(output, "test.typ,500\n");
}
#[test]
fn test_format_single_file() {
let results = vec![(
"test.typ".to_string(),
Count {
words: 100,
characters: 500,
},
)];
let output = format(&results, DisplayMode::Auto, CountMode::Both);
assert_eq!(output, "file,words,characters\ntest.typ,100,500\n");
}
#[test]
fn test_format_multiple_files() {
let results = vec![
(
"file1.typ".to_string(),
Count {
words: 100,
characters: 500,
},
),
(
"file2.typ".to_string(),
Count {
words: 200,
characters: 1000,
},
),
];
let output = format(&results, DisplayMode::Auto, CountMode::Both);
assert!(output.starts_with("file,words,characters\n"));
assert!(output.contains("file1.typ,100,500\n"));
assert!(output.contains("file2.typ,200,1000\n"));
}
#[test]
fn test_format_display_mode_total() {
let results = vec![
(
"file1.typ".to_string(),
Count {
words: 100,
characters: 500,
},
),
(
"file2.typ".to_string(),
Count {
words: 200,
characters: 1000,
},
),
];
let output = format(&results, DisplayMode::Total, CountMode::Both);
assert_eq!(output, "file,words,characters\ntotal,300,1500\n");
}
#[test]
fn test_format_words_only() {
let results = vec![(
"test.typ".to_string(),
Count {
words: 42,
characters: 200,
},
)];
let output = format(&results, DisplayMode::Auto, CountMode::Words);
assert_eq!(output, "file,words\ntest.typ,42\n");
assert!(!output.contains("characters"));
}
#[test]
fn test_format_characters_only() {
let results = vec![(
"test.typ".to_string(),
Count {
words: 42,
characters: 200,
},
)];
let output = format(&results, DisplayMode::Auto, CountMode::Characters);
assert_eq!(output, "file,characters\ntest.typ,200\n");
assert!(!output.contains("words"));
}
#[test]
fn test_format_total_single_file() {
let results = vec![(
"test.typ".to_string(),
Count {
words: 100,
characters: 500,
},
)];
let output = format(&results, DisplayMode::Total, CountMode::Both);
assert_eq!(output, "file,words,characters\ntest.typ,100,500\n");
}
}