use std::io::{self, Write as _};
use colored::Colorize;
use super::formatting::print_formatted;
use crate::types::{Comment, OutputFormat};
pub fn print_comments(comments: &[Comment], format: OutputFormat) {
print_formatted(comments, format, |comments| {
if comments.is_empty() {
let _ = writeln!(io::stdout(), "No comments.");
return;
}
for c in comments {
let _ = writeln!(
io::stdout(),
"{} #{} by {} ({})",
"Comment".bold(),
c.count,
c.creator.as_deref().unwrap_or("unknown").cyan(),
c.creation_time.as_deref().unwrap_or(""),
);
if c.is_private {
let _ = writeln!(io::stdout(), " {}", "[PRIVATE]".red());
}
let _ = writeln!(io::stdout());
for line in c.text.lines() {
let _ = writeln!(io::stdout(), " {line}");
}
let _ = writeln!(io::stdout());
let _ = writeln!(io::stdout(), "{}", "─".repeat(60));
}
});
}
#[cfg(test)]
#[expect(clippy::unwrap_used)]
mod tests {
use super::print_comments;
use crate::types::{Comment, OutputFormat};
fn make_comment(count: u64, text: &str) -> Comment {
Comment {
id: count + 100,
bug_id: 42,
text: text.into(),
creator: Some("commenter@example.com".into()),
creation_time: Some("2025-02-01T08:00:00Z".into()),
count,
is_private: false,
}
}
#[test]
fn print_comments_json_empty() {
let comments: Vec<Comment> = vec![];
let json = serde_json::to_string_pretty(&comments).unwrap();
assert_eq!(json, "[]");
}
#[test]
fn print_comments_json_one_comment() {
let comments = vec![make_comment(0, "First comment text")];
let json = serde_json::to_string_pretty(&comments).unwrap();
let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
assert_eq!(parsed[0]["text"], "First comment text");
assert_eq!(parsed[0]["count"], 0);
assert_eq!(parsed[0]["creator"], "commenter@example.com");
}
#[test]
fn print_comments_json_private_flag() {
let mut comment = make_comment(1, "secret");
comment.is_private = true;
let json = serde_json::to_string(&comment).unwrap();
let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
assert_eq!(parsed["is_private"], true);
}
#[cfg(unix)]
#[tokio::test]
async fn print_comments_table_empty_says_no_comments() {
let _lock = crate::ENV_LOCK.lock().await;
let ((), output) = crate::test_helpers::capture_stdout(async {
print_comments(&[], OutputFormat::Table);
})
.await;
assert!(output.contains("No comments."));
}
#[cfg(unix)]
#[tokio::test]
async fn print_comments_json_empty_renders_empty_array() {
let _lock = crate::ENV_LOCK.lock().await;
let ((), output) = crate::test_helpers::capture_stdout(async {
print_comments(&[], OutputFormat::Json);
})
.await;
let parsed = crate::test_helpers::extract_json(&output);
assert!(parsed.is_array());
assert_eq!(parsed.as_array().unwrap().len(), 0);
}
#[cfg(unix)]
#[tokio::test]
async fn print_comments_table_renders_comment_fields() {
let _lock = crate::ENV_LOCK.lock().await;
let mut c = make_comment(2, "Line one\nLine two");
c.is_private = true;
let comments = vec![c];
let ((), output) = crate::test_helpers::capture_stdout(async {
print_comments(&comments, OutputFormat::Table);
})
.await;
assert!(output.contains("Comment"));
assert!(output.contains("#2"));
assert!(output.contains("commenter@example.com"));
assert!(output.contains("2025-02-01T08:00:00Z"));
assert!(output.contains("[PRIVATE]"));
assert!(output.contains("Line one"));
assert!(output.contains("Line two"));
assert!(output.contains('─'));
}
#[cfg(unix)]
#[tokio::test]
async fn print_comments_table_handles_missing_creator_and_unicode() {
let _lock = crate::ENV_LOCK.lock().await;
let comments = vec![Comment {
id: 1,
bug_id: 42,
text: "héllo, wörld".into(),
creator: None,
creation_time: None,
count: 0,
is_private: false,
}];
let ((), output) = crate::test_helpers::capture_stdout(async {
print_comments(&comments, OutputFormat::Table);
})
.await;
assert!(output.contains("unknown"));
assert!(output.contains("héllo, wörld"));
assert!(!output.contains("[PRIVATE]"));
}
#[cfg(unix)]
#[tokio::test]
async fn print_comments_json_one_comment_via_print() {
let _lock = crate::ENV_LOCK.lock().await;
let comments = vec![make_comment(7, "json body")];
let ((), output) = crate::test_helpers::capture_stdout(async {
print_comments(&comments, OutputFormat::Json);
})
.await;
let parsed = crate::test_helpers::extract_json(&output);
assert_eq!(parsed[0]["count"], 7);
assert_eq!(parsed[0]["text"], "json body");
assert_eq!(parsed[0]["bug_id"], 42);
}
}