use crate::info::utils::info_field::InfoField;
use onefetch_manifest::Manifest;
use serde::Serialize;
const NUMBER_OF_WORDS_PER_LINE: usize = 5;
#[derive(Serialize)]
pub struct DescriptionInfo {
pub description: Option<String>,
}
impl DescriptionInfo {
pub fn new(manifest: Option<&Manifest>) -> Self {
let description = match manifest {
Some(m) => m.description.clone(),
None => None,
};
Self { description }
}
}
#[typetag::serialize]
impl InfoField for DescriptionInfo {
fn value(&self) -> String {
match &self.description {
Some(description) => {
let left_pad = self.title().len() + 2;
break_sentence_into_lines(description, left_pad)
}
None => String::new(),
}
}
fn title(&self) -> String {
"Description".into()
}
}
fn break_sentence_into_lines(sentence: &str, left_pad: usize) -> String {
let words: Vec<&str> = sentence.split_whitespace().collect();
let mut lines = Vec::new();
for (i, chunk) in words.chunks(NUMBER_OF_WORDS_PER_LINE).enumerate() {
let line = if i == 0 {
chunk.join(" ")
} else {
format!("{:>width$}{}", "", chunk.join(" "), width = left_pad)
};
lines.push(line);
}
lines.join("\n")
}
#[cfg(test)]
mod test {
use super::*;
use onefetch_manifest::ManifestType;
use rstest::rstest;
#[test]
fn should_display_description() {
let description_info = DescriptionInfo::new(Some(&Manifest {
manifest_type: ManifestType::Cargo,
name: None,
description: Some("test".into()),
number_of_dependencies: 0,
version: Some("0.1.0".into()),
license: None,
}));
assert_eq!(description_info.value(), "test".to_string());
}
#[rstest]
#[case("Hello", "Hello")]
#[case(
"Hello world, how are you doing?",
"Hello world, how are you\n doing?"
)]
#[case(
"This is a long sentence that needs to be broken into multiple lines.",
"This is a long sentence\n that needs to be broken\n into multiple lines."
)]
fn test_break_sentence_into_lines(#[case] sentence: &str, #[case] expected_result: &str) {
assert_eq!(break_sentence_into_lines(sentence, 4), expected_result);
}
}