use super::*;
impl MarkdownFormatter {
pub(super) fn format_diff(&self, diff: &crate::diff::DomainDiff) -> String {
let dash = "\u{2014}";
let mut output = Vec::new();
let opt_or_dash = |o: &Option<String>| -> String {
match o {
Some(v) => format!("{}", MdSafe(v)),
None => dash.to_string(),
}
};
let list_or_dash = |v: &Vec<String>| -> String {
if v.is_empty() {
dash.to_string()
} else {
v.iter()
.map(|s| format!("`{}`", MdSafe(s)))
.collect::<Vec<_>>()
.join(", ")
}
};
output.push(format!(
"## Domain Comparison: {} vs {}",
MdSafe(&diff.domain_a),
MdSafe(&diff.domain_b)
));
output.push(String::new());
output.push("### Registration".to_string());
output.push(String::new());
output.push(format!(
"| Field | {} | {} |",
MdSafe(&diff.domain_a),
MdSafe(&diff.domain_b)
));
output.push("| --- | --- | --- |".to_string());
let reg = &diff.registration;
output.push(format!(
"| Registrar | {} | {} |",
opt_or_dash(®.registrar.0),
opt_or_dash(®.registrar.1)
));
output.push(format!(
"| Organization | {} | {} |",
opt_or_dash(®.organization.0),
opt_or_dash(®.organization.1)
));
output.push(format!(
"| Created | {} | {} |",
opt_or_dash(®.created.0),
opt_or_dash(®.created.1)
));
output.push(format!(
"| Expires | {} | {} |",
opt_or_dash(®.expires.0),
opt_or_dash(®.expires.1)
));
output.push(String::new());
output.push("### DNS".to_string());
output.push(String::new());
output.push(format!(
"| Field | {} | {} |",
MdSafe(&diff.domain_a),
MdSafe(&diff.domain_b)
));
output.push("| --- | --- | --- |".to_string());
let dns = &diff.dns;
output.push(format!(
"| Resolves | {} | {} |",
if dns.resolves.0 { "yes" } else { "no" },
if dns.resolves.1 { "yes" } else { "no" }
));
let a_recs_a = list_or_dash(&dns.a_records.0);
let a_recs_b = list_or_dash(&dns.a_records.1);
output.push(format!("| A Records | {} | {} |", a_recs_a, a_recs_b));
let ns_a = list_or_dash(&dns.nameservers.0);
let ns_b = list_or_dash(&dns.nameservers.1);
output.push(format!("| Nameservers | {} | {} |", ns_a, ns_b));
output.push(String::new());
output.push("### SSL".to_string());
output.push(String::new());
output.push(format!(
"| Field | {} | {} |",
MdSafe(&diff.domain_a),
MdSafe(&diff.domain_b)
));
output.push("| --- | --- | --- |".to_string());
let ssl = &diff.ssl;
output.push(format!(
"| Issuer | {} | {} |",
opt_or_dash(&ssl.issuer.0),
opt_or_dash(&ssl.issuer.1)
));
output.push(format!(
"| Valid Until | {} | {} |",
opt_or_dash(&ssl.valid_until.0),
opt_or_dash(&ssl.valid_until.1)
));
output.push(format!(
"| Days Remaining | {} | {} |",
ssl.days_remaining
.0
.map(|d| d.to_string())
.as_deref()
.unwrap_or(dash),
ssl.days_remaining
.1
.map(|d| d.to_string())
.as_deref()
.unwrap_or(dash)
));
output.push(format!(
"| Valid | {} | {} |",
ssl.is_valid
.0
.map(|v| if v { "yes" } else { "no" })
.unwrap_or(dash),
ssl.is_valid
.1
.map(|v| if v { "yes" } else { "no" })
.unwrap_or(dash)
));
output.join("\n")
}
}
#[cfg(test)]
mod tests {
use crate::diff::{DnsDiff, DomainDiff, RegistrationDiff, SslDiff};
use crate::output::markdown::MarkdownFormatter;
fn diff_with_nameservers(ns: Vec<String>) -> DomainDiff {
DomainDiff {
domain_a: "a.com".to_string(),
domain_b: "b.com".to_string(),
registration: RegistrationDiff {
registrar: (None, None),
organization: (None, None),
created: (None, None),
expires: (None, None),
},
dns: DnsDiff {
a_records: (Vec::new(), Vec::new()),
nameservers: (ns, Vec::new()),
resolves: (true, false),
},
ssl: SslDiff {
issuer: (None, None),
valid_until: (None, None),
days_remaining: (None, None),
is_valid: (None, None),
},
}
}
#[test]
fn test_markdown_diff_list_renders_per_item_code_spans() {
let diff = diff_with_nameservers(vec![
"ns1.example.com".to_string(),
"ns2.example.com".to_string(),
]);
let output = MarkdownFormatter::new().format_diff(&diff);
assert!(
output.contains("`ns1.example.com`, `ns2.example.com`"),
"expected per-item code spans, got:\n{}",
output
);
assert!(
!output.contains("ns1.example.com', 'ns2.example.com"),
"separator backticks were corrupted into apostrophes:\n{}",
output
);
}
}